12
\$\begingroup\$

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

\$\endgroup\$
20
  • 1
    \$\begingroup\$ 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. \$\endgroup\$
    – l4m2
    Oct 26, 2018 at 15:43
  • 3
    \$\begingroup\$ Also I don't think ppcg is a word in dictionary \$\endgroup\$
    – l4m2
    Oct 26, 2018 at 16:18
  • 1
    \$\begingroup\$ 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? \$\endgroup\$ Oct 26, 2018 at 20:27
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Oct 27, 2018 at 9:54
  • 2
    \$\begingroup\$ @PaŭloEbermann Alright, I removed it \$\endgroup\$
    – kepe
    Oct 27, 2018 at 10:03

16 Answers 16

5
\$\begingroup\$

Japt, 13 bytes

¸
mά
VøUÎ ©V

Try it online!

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

05AB1E, 16 bytes

ð¡©ηʒJ®€нJηså}θJ

Try it online!

\$\endgroup\$
11
  • 1
    \$\begingroup\$ Why did it change to ð¡ instead of # in your last edit? Some special test cases I'm not taking into account? \$\endgroup\$ Oct 26, 2018 at 12:59
  • \$\begingroup\$ @KevinCruijssen: Because # would fail for single word input outputting the input instead of an empty string. \$\endgroup\$
    – Emigna
    Oct 26, 2018 at 13:01
  • \$\begingroup\$ 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"]). \$\endgroup\$ Oct 26, 2018 at 13:04
  • \$\begingroup\$ @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. \$\endgroup\$
    – Emigna
    Oct 26, 2018 at 13:10
  • 1
    \$\begingroup\$ @KamilDrakari: Works now though. \$\endgroup\$
    – Emigna
    Oct 26, 2018 at 22:16
2
\$\begingroup\$

Haskell, 51 48 bytes

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
\$\endgroup\$
1
  • \$\begingroup\$ Since you're not using x, composing (\w-> ...).words would be shorter. \$\endgroup\$
    – xnor
    Oct 27, 2018 at 0:02
2
\$\begingroup\$

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
\$\endgroup\$
2
  • \$\begingroup\$ You aren't required to output "IMPOSSIBLE" now \$\endgroup\$
    – kepe
    Oct 26, 2018 at 12:20
  • \$\begingroup\$ @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 \$\endgroup\$ Oct 26, 2018 at 18:03
1
\$\begingroup\$

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* ?
$1

Reduce the words on the first line to their initial letters.

+`^(.+)(\w.*¶\1 )
$1 $2

Insert spaces to match the original words, if possible.

!`^(.+)(?=¶\1 )

Output the first line if it is a prefix of the second line.

\$\endgroup\$
2
  • \$\begingroup\$ For ppcg paints, output is invalid, it should output nothing since pp only spells a portion of the first word, instead of all of it \$\endgroup\$
    – kepe
    Oct 26, 2018 at 12:50
  • \$\begingroup\$ @FireCubez Sorry, I was working off an older version of the question. \$\endgroup\$
    – Neil
    Oct 26, 2018 at 13:01
1
\$\begingroup\$

Perl 6, 56 bytes

$!=[~] m:g{<<.};say $! if m:g{<<\w+}.map({$_ eq $!}).any

Try it online!

Previously regexes were confusing and unusable to me. Suddenly I understand them perfectly. What happened to me :P

Fulfills choice 1.

\$\endgroup\$
1
  • \$\begingroup\$ Sadly, I'm still at the stage where regexes are simply madness. Unfortunately, this fails the ppcgpaints test, otherwise I would have suggested something like $!∈.words for the if condition \$\endgroup\$
    – Jo King
    Oct 26, 2018 at 17:51
1
\$\begingroup\$

K (ngn/k), 40 bytes

First option:

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

Try it online!

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

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()}}
\$\endgroup\$
2
  • \$\begingroup\$ Which of the 2 choices does this program do? \$\endgroup\$
    – kepe
    Oct 26, 2018 at 15:52
  • \$\begingroup\$ @FireCubez Updated. \$\endgroup\$ Oct 26, 2018 at 20:13
1
\$\begingroup\$

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); ...]
        Ɗ - last three links as a monad (i.e. f(v)):
     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
\$\endgroup\$
4
  • \$\begingroup\$ What do you mean by "print the first word"? It needs to find the acronym if one exists, does it do that? \$\endgroup\$
    – kepe
    Oct 26, 2018 at 19:50
  • \$\begingroup\$ Fails for "ppcg paints cool galaxies pouring acid into not the sky", should print "ppcg paints" or "ppcgpaints" \$\endgroup\$
    – kepe
    Oct 26, 2018 at 20:24
  • \$\begingroup\$ Oh, I missed the adjoining words requirement :( \$\endgroup\$ Oct 26, 2018 at 20:37
  • \$\begingroup\$ Fixed it up to meet this requirement. \$\endgroup\$ Oct 26, 2018 at 20:46
1
\$\begingroup\$

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'

\$\endgroup\$
2
  • \$\begingroup\$ Fail on increase i \$\endgroup\$
    – l4m2
    Oct 27, 2018 at 15:47
  • \$\begingroup\$ @l4m2, now fixed. \$\endgroup\$ Oct 29, 2018 at 21:33
1
\$\begingroup\$

Vyxal, 8 bytes

⌈:¦$∩h¦↔

Try it Online!

\$\endgroup\$
0
\$\begingroup\$

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!

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

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.
\$\endgroup\$
0
\$\begingroup\$

Ruby -apl, 57 bytes

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

Try it online!

\$\endgroup\$
0
\$\begingroup\$

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!

\$\endgroup\$
0
\$\begingroup\$

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
\$\endgroup\$
12
  • \$\begingroup\$ you are allowed to turn it into a lambda \$\endgroup\$
    – ASCII-only
    Jan 2, 2019 at 1:26
  • \$\begingroup\$ Can ::: be replaced with ++? Also, List[String] -> Seq[Any]? \$\endgroup\$
    – ASCII-only
    Jan 2, 2019 at 1:29
  • 1
    \$\begingroup\$ 100? \$\endgroup\$
    – ASCII-only
    Jan 2, 2019 at 1:47
  • \$\begingroup\$ @ASCII-only, cool! This solution beats Python. :) \$\endgroup\$
    – Dr Y Wit
    Jan 3, 2019 at 12:37
  • \$\begingroup\$ Mind adding the code sometime? IMO it's a bit weird seeing the bytecount without seeing the solution \$\endgroup\$
    – ASCII-only
    Jan 4, 2019 at 0:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.