# Introduction

A recursive acronym is an acronym that contains or refers to itself, for example: Fish could be a recursive acronym for Fish is shiny hero, notice how that also contains the acronym itself. Another example is Hi -> Hi igloo. Or even ppcg paints -> ppcg paints cool galaxies pouring acid into night time stars

So basically, a sentence is a recursive acronym if the first letters of each of the words spell out the first word or words.

# Challenge

Make a program that takes a string of 1 or more words separated by a space character, and outputs a recursive acronym, or an empty string if it's impossible. It is impossible to make a recursive acronym for a string like, for example, ppcg elephant because you would start by taking the p from ppcg then adding that to the acronym, then taking the e from elephant. But now we have a contradiction, since the acronym currently spells out "pe..", which conflicts with "pp..". That's also the case with, for example, hi. You would take the h from hi, but the sentence is now over and there are no more letters to spell out hi and we are just left with h which doesn't match hi. (The string needs an amount of words more than or equal to the amount of letters in the acronym)

Input and output are not case sensitive

# Restrictions

• Anything inputted into your program will be valid English words. But you must make sure to output valid English words too (you can use a database or just store a word for each of the 26 letters)
• Standard loopholes and default IO rules apply

# Test Cases

hi igloo -> hi
ppcg paints -> (impossible)
ppcg paints cool giraffes -> ppcg
ppcg paints cool galaxies pouring acid into night time stars -> ppcgpaints
ppcg paints cool galaxies pouring acid into night time -> ppcg
ppcg questions professional pool challengers greatly -> (impossible)
I -> I

# Scoring

This is , so the smallest source code in bytes wins

• Q, q [kyoo] noun, plural Q's or Qs, q's or qs. the 17th letter of the English alphabet, a consonant. any spoken sound represented by the letter Q or q, as in quick, acquit, or Iraq. something having the shape of a Q. – l4m2 Oct 26 '18 at 15:43
• Also I don't think ppcg is a word in dictionary – l4m2 Oct 26 '18 at 16:18
• Okay, one of those test cases didn't turn out as I expected. Just to make sure neither of us is making a mistake ppcg paints cool galaxies pouring acid into night time would be "ppcgpaint" when made into an acronym, but the output should be ppcg even though it's only a partial match? – Kamil Drakari Oct 26 '18 at 20:27
• As all current solutions are taking the first option ("find acronym"), and the "find sentence" option is much more complicated (so no way of being competitive with the first one – you need some word list, to start with), I would suggest to remove it from this challenge and make it its own question. – Paŭlo Ebermann Oct 27 '18 at 9:54
• @PaŭloEbermann Alright, I removed it – FireCubez Oct 27 '18 at 10:03

# Japt, 13 bytes

¸
mÎ¬

Try it online!

• 11 bytes – Shaggy Oct 26 '18 at 13:58
• This fails on the ppcg paints cool galaxies pouring acid into night time stars test case – Kamil Drakari Oct 26 '18 at 15:32
• here's a version that works for that test case, but it's not golfed – Kamil Drakari Oct 26 '18 at 15:54
• My previous 13 bytes solution was correct Dx\ – Luis felipe De jesus Munoz Oct 26 '18 at 17:52
• The current version just checks that the acronym contains the first word, which results in some new issues – Kamil Drakari Oct 26 '18 at 19:57

# 05AB1E, 16 bytes

Try it online!

• Why did it change to ð¡ instead of # in your last edit? Some special test cases I'm not taking into account? – Kevin Cruijssen Oct 26 '18 at 12:59
• @KevinCruijssen: Because # would fail for single word input outputting the input instead of an empty string. – Emigna Oct 26 '18 at 13:01
• Ah yeah, that was it. I remember asking something similar before. I still think # should act the same as ð¡.. Is there a use-case you can think of where you want to split a string on spaces, but if it doesn't contain a space, it should remain the string (instead of the string wrapped in a list)? Other people reading this; FYI: Using # (split on space) on a string without spaces results in the string as is (i.e. "test" -> "test"). Using ð¡ (split on space) on a string without spaces results in the string wrapped in a list (i.e. "test" -> ["test"]). – Kevin Cruijssen Oct 26 '18 at 13:04
• @KevinCruijssen: I think it's mainly due to # also being used as quit if true (which is its main function). If # returned false, you probably wouldn't want the value checked to be wrapped in a list, left on the stack. – Emigna Oct 26 '18 at 13:10
• @KamilDrakari: Works now though. – Emigna Oct 26 '18 at 22:16

Edit: -3 bytes thanks to @xnor.

(\w->[r|p<-scanl1(++)w,map(!!0)w==p,r<-p]).words

Finds acronym.

Try it online!

\w->            .words -- let 'w' be the input list split into words
p<-scanl1(++)w      -- loop 'p' through the list starting with the first word
--  and appending the next words one by one, e.g.
--  "Fish","is","shiny","hero" -> "Fish","Fishis","Fishisshiny","Fishisshinyhero"
,map(!!0)w==p     -- if the word made out of the first characters of the
--  words of 'w' equal 'p'
[r|   r<-p]          -- return the letters of 'p' - if the check before
--  never evaluates to True then no letters, i.e. the
--  the empty string is returned
• Since you're not using x, composing (\w-> ...).words would be shorter. – xnor Oct 27 '18 at 0:02

# Perl 6, 50 42 58 49 bytes

-9 bytes thanks to nwellnhof

{~first {m:g/<<./.join~~/^$^a/},[R,] [\~] .words} Try it online! First option. I'm exploiting the fact the ord only returns the ordinal value of first letter of a string, while chrs takes a list of ords and returns a string. Or the regex from moonheart's answer is shorter :(. For reference, the previous answer was .words>>.ord.chrs instead of [~] m:g/<<./ ### Explanation: {~first {m:g/<<./.join~~/^$^a/},[R,] [\~] .words}
{                                               } # Anonymous code block
first  # Find the first
[R,] [\~] .words  # Of the reverse of the triangular joined words
{                    }  # That matches:
m:g/   /   # Match all from the original string
<<.    # Single letters after a word boundary
.join    # Joined
~~/^$^a/ # And starts with the given word ~ # And stringify Nil to an empty string • You aren't required to output "IMPOSSIBLE" now – FireCubez Oct 26 '18 at 12:20 • @Jo King I can do regexes, but for the life of me I can't seem to think with all the operators. I keep forgetting the x operator exists, for example :P – moonheart08 Oct 26 '18 at 18:03 # Retina 0.8.2, 60 bytes ^$'¶
\G(\w)\w* ?
$1 +^(.+)(\w.*¶\1 )$1 $2 !^(.+)(?=¶\1 ) Try it online! Finds the recursive acronym, if any. Explanation: ^$'¶

Duplicate the input.

\G(\w)\w* ?

# K (ngn/k), 40 bytes

First option:

{$[1=#:x;x;$[(*:t)~,/*:'t:" "\x;*:t;]]}

Try it online!

• Which of the 2 options does this work on? – FireCubez Oct 26 '18 at 15:54
• The first, outputs acronym from string input. I'll edit my post to clarify – Thaufeki Oct 26 '18 at 15:58

# Rust, 155, try it online!

Selected: Problem 1: Finding acronym

type S=String;fn f(t:&str)->S{let l=t.to_lowercase();let w=l.split(' ').fold(S::new(),|a,b|a+&b[..1])+" ";if (l+" ").contains(w.as_str()){w}else{S::new()}}

Ungolfed, just a bit:

fn f(t: &str) -> String {
let l = t.to_lowercase();
let w = l.split(' ').fold(String::new(), |a, b| a + &b[0..1]) + " ";
if (l + " ").contains(w.as_str()) {
w
} else {
String::new()
}
}

Or if we can assume that the input is all lowercase, just 130:

type S=String;fn f(l:S)->S{let w=l.split(' ').fold(S::new(),|a,b|a+&b[..1])+" ";if (l+" ").contains(&w.as_str()){w}else{S::new()}}
• Which of the 2 choices does this program do? – FireCubez Oct 26 '18 at 15:52
• @FireCubez Updated. – Hannes Karppila Oct 26 '18 at 20:13

# Jelly, 9 bytes

Ḳµ;\fZḢWƊ

A full-program printing the recursive abbreviation if it is possible.

Try it online!

### How?

Ḳµ;\fZḢWƊ - Main Link: list of characters
Ḳ         - split at space (let's call this v)
µ        - start a new monadic chain (i.e. f(v)):
\      - cumulative reduce v with:
;       -   concatenation -> [v(1), v(1);v(2), v(1);v(2);v(3); ...]
Z    -   transpose -> [[v(1)[1], v(2)[1], ...],[v(1)[1],v(2)[2],...],...]
Ḣ   -   head -> [v(1)[1], v(2)[1], ...] ... i.e. 'the potential abbreviation'
W  -   wrap in a list -> ['the potential abbreviation']
f     - filter discard those from the left list that are not in the right list
- implicit print -- a list of length 0 prints nothing
-                   while a list of a single item prints that item
• What do you mean by "print the first word"? It needs to find the acronym if one exists, does it do that? – FireCubez Oct 26 '18 at 19:50
• Fails for "ppcg paints cool galaxies pouring acid into not the sky", should print "ppcg paints" or "ppcgpaints" – FireCubez Oct 26 '18 at 20:24
• Oh, I missed the adjoining words requirement :( – Jonathan Allan Oct 26 '18 at 20:37
• Fixed it up to meet this requirement. – Jonathan Allan Oct 26 '18 at 20:46

# JavaScript [ES6], 74 bytes

s=>s.split .map(w=>(b+='('+w,e+=')?',t+=w[0]),b=e=t='')&&t.match(b+e)[0]

Creates a regular expression to match on. See examples in code.

All test cases:

let f=

s=>s.split `.map(w=>(b+='('+w,e+=')?',t+=w[0]),b=e=t='')&&t.match(b+e)[0]

console.log(f('hi igloo'))
// 'hi'.match('(hi(igloo)?)?')[0] == 'hi'

console.log(f('ppcg paints'))
// 'pp'.match('(ppcg(paints)?)?')[0] == ''

console.log(f('ppcg paints cool giraffes'))
// 'ppcg'.match('(ppcg(paints(cool(giraffes)?)?)?)?')[0] == 'ppcg'

console.log(f('ppcg paints cool galaxies pouring acid into night time stars'))
// 'ppcgpaints'.match('(ppcg(paints(cool(galaxies(pouring(acid(into(night(time(stars)?)?)?)?)?)?)?)?)?)?')[0] == 'ppcgpaints'

console.log(f('ppcg paints cool galaxies pouring acid into night time'))
// 'ppcgpaint'.match('(ppcg(paints(cool(galaxies(pouring(acid(into(night(time)?)?)?)?)?)?)?)?)?')[0] == 'ppcg'

console.log(f('ppcg questions professional pool challengers greatly'))
// 'pqppcg'.match('(ppcg(questions(professional(pool(challengers(greatly)?)?)?)?)?)?')[0] == ''

console.log(f('I'))
// 'I'.match('(I)?')[0] == 'I'

console.log(f('increase i'))
// 'ii'.match('(increase(i)?)?')[0] == ''

console.log(f('i increase'))
// 'ii'.match('(i(increase)?)?')[0] == 'i'

• Fail on increase i – l4m2 Oct 27 '18 at 15:47
• @l4m2, now fixed. – Rick Hitchcock Oct 29 '18 at 21:33

# Python 2, 106 bytes

First option - finding recursive acronym.
Returns result in list.

I=input().split()
print[' '.join(I[:i])for i in range(1,-~len(I))if[j[0]for j in I]==list(''.join(I[:i]))]

Try it online!

# Python 2, 120 bytes

First option - finding recursive acronym.

def F(I,a=[],r=''):
for j in I.split():
a+=j,
if list(''.join(a))==[i[0]for i in I.split()]:r=' '.join(a)
return r

Try it online!

• You aren't required to output "IMPOSSIBLE" as per @JoKing 's request, that might decrease your byte count – FireCubez Oct 26 '18 at 12:21
• Single letters like 'I' don't work, it should output that single letter – FireCubez Oct 26 '18 at 13:14
• @FireCubez fixed – Dead Possum Oct 26 '18 at 13:33

# Javascript, 71 bytes

Approach 1

l=s=>{p=s.split(' ');k=p.reduce((r,x)=>r+x[0],'');return k==p[0]?k:''}

Ungolfed:

l=s=>{
p = s.split(' ');
k = p.reduce((r,x)=>r+x[0],'');
return k==p[0] ? k : '';
}
• Split the string by space.
• Create new string by taking first character from each word.
• Compare it with the first word.

# Ruby-apl, 57 bytes

$_=y="";$F.all?{|w|$F.map(&:chr).join[/^#{y+=w}/]?$_=y:p}

Try it online!

# Python 2, 109 bytes

def f(s,J=''.join):s=s.split();return[J(s[:i])for i in range(len(s)+1)if J(zip(*s)[0]).find(J(s[:i]))==0][-1]

Try it online!

# Scala, 76 bytes

Solution for simple case (acronyms without whitespaces)

def^(s:String)={val l=s.split(" ");if(l(0)==l.map(_(0)).mkString)l(0)else""}

# Scala, 144 bytes 100 bytes (see solution by ASCII-only in the comments)

def^(s:String)={val l=s.split(" ");l.scanLeft(List[String]())(_:::List(_)).find(_.mkString==l.map(_(0)).mkString).map(_.mkString).getOrElse("")}

Test in REPL

scala> def^(s:String)={val l=s.split(" ");if(l(0)==l.map(_(0)).mkString)l(0)else""}
$up: (s: String)String scala> ^("hi igloo") res12: String = hi scala> ^("ppcg paints cool giraffes") res13: String = ppcg scala> ^("ppcg paints Xcool giraffes") res14: String = "" scala> ^("ppcg paints cool galaxies pouring acid into night time stars") res15: String = "" scala> scala> def^(s:String)={val l=s.split(" ");l.scanLeft(List[String]())(_:::List(_)).find(_.mkString==l.map(_(0)).mkString).map(_.mkString).getOrElse("")}$up: (s: String)String

scala> ^("hi igloo")
res16: String = hi

scala> ^("ppcg paints cool giraffes")
res17: String = ppcg

scala> ^("ppcg paints Xcool giraffes")
res18: String = ""

scala> ^("ppcg paints cool galaxies pouring acid into night time stars")
res19: String = ppcgpaints
• you are allowed to turn it into a lambda – ASCII-only Jan 2 '19 at 1:26
• Can ::: be replaced with ++? Also, List[String] -> Seq[Any]? – ASCII-only Jan 2 '19 at 1:29
• 100? – ASCII-only Jan 2 '19 at 1:47
• @ASCII-only, cool! This solution beats Python. :) – Dr Y Wit Jan 3 '19 at 12:37
• Mind adding the code sometime? IMO it's a bit weird seeing the bytecount without seeing the solution – ASCII-only Jan 4 '19 at 0:50