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

15 Answers 15

5
\$\begingroup\$

Japt, 13 bytes

¸
mά
VøUÎ ©V

Try it online!

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

05AB1E, 16 bytes

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

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Why did it change to ð¡ instead of # in your last edit? Some special test cases I'm not taking into account? \$\endgroup\$ – Kevin Cruijssen Oct 26 '18 at 12:59
  • \$\begingroup\$ @KevinCruijssen: Because # would fail for single word input outputting the input instead of an empty string. \$\endgroup\$ – Emigna Oct 26 '18 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\$ – Kevin Cruijssen Oct 26 '18 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 '18 at 13:10
  • 1
    \$\begingroup\$ @KamilDrakari: Works now though. \$\endgroup\$ – Emigna Oct 26 '18 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\$
  • \$\begingroup\$ Since you're not using x, composing (\w-> ...).words would be shorter. \$\endgroup\$ – xnor Oct 27 '18 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\$
  • \$\begingroup\$ You aren't required to output "IMPOSSIBLE" now \$\endgroup\$ – FireCubez Oct 26 '18 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\$ – moonheart08 Oct 26 '18 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\$
  • \$\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\$ – FireCubez Oct 26 '18 at 12:50
  • \$\begingroup\$ @FireCubez Sorry, I was working off an older version of the question. \$\endgroup\$ – Neil Oct 26 '18 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\$
  • \$\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 '18 at 17:51
1
\$\begingroup\$

K (ngn/k), 40 bytes

First option:

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

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Which of the 2 options does this work on? \$\endgroup\$ – FireCubez Oct 26 '18 at 15:54
  • \$\begingroup\$ The first, outputs acronym from string input. I'll edit my post to clarify \$\endgroup\$ – Thaufeki Oct 26 '18 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\$
  • \$\begingroup\$ Which of the 2 choices does this program do? \$\endgroup\$ – FireCubez Oct 26 '18 at 15:52
  • \$\begingroup\$ @FireCubez Updated. \$\endgroup\$ – Hannes Karppila Oct 26 '18 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\$
  • \$\begingroup\$ What do you mean by "print the first word"? It needs to find the acronym if one exists, does it do that? \$\endgroup\$ – FireCubez Oct 26 '18 at 19:50
  • \$\begingroup\$ Fails for "ppcg paints cool galaxies pouring acid into not the sky", should print "ppcg paints" or "ppcgpaints" \$\endgroup\$ – FireCubez Oct 26 '18 at 20:24
  • \$\begingroup\$ Oh, I missed the adjoining words requirement :( \$\endgroup\$ – Jonathan Allan Oct 26 '18 at 20:37
  • \$\begingroup\$ Fixed it up to meet this requirement. \$\endgroup\$ – Jonathan Allan Oct 26 '18 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\$
  • \$\begingroup\$ Fail on increase i \$\endgroup\$ – l4m2 Oct 27 '18 at 15:47
  • \$\begingroup\$ @l4m2, now fixed. \$\endgroup\$ – Rick Hitchcock Oct 29 '18 at 21:33
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\$
  • \$\begingroup\$ You aren't required to output "IMPOSSIBLE" as per @JoKing 's request, that might decrease your byte count \$\endgroup\$ – FireCubez Oct 26 '18 at 12:21
  • \$\begingroup\$ Single letters like 'I' don't work, it should output that single letter \$\endgroup\$ – FireCubez Oct 26 '18 at 13:14
  • \$\begingroup\$ @FireCubez fixed \$\endgroup\$ – Dead Possum Oct 26 '18 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\$
  • \$\begingroup\$ you are allowed to turn it into a lambda \$\endgroup\$ – ASCII-only Jan 2 at 1:26
  • \$\begingroup\$ Can ::: be replaced with ++? Also, List[String] -> Seq[Any]? \$\endgroup\$ – ASCII-only Jan 2 at 1:29
  • 1
    \$\begingroup\$ 100? \$\endgroup\$ – ASCII-only Jan 2 at 1:47
  • \$\begingroup\$ @ASCII-only, cool! This solution beats Python. :) \$\endgroup\$ – Dr Y Wit Jan 3 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 at 0:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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