# Bring out the inner llama of a sentence

Your objective is to take input like

Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good.


and create an array of the indexes of the string where the letters that make up the word "Llama" appear (one of each in order). For example, let me show the letters pointed at with carets to show the indexes:

Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good.
^                      ^        ^                            ^        ^


So the array would look like:

[44, 67, 76, 105, 114]


(If your application uses a indexing that's not 0-based, the numbers will look different. That's fine.)

If the text has no llama, then the array should be empty, nil, null, or undefined.

Any code language is accepted. This is a contest, so the least characters win!

• @TheWobbuffet You keep changing your username and picture. There was a time when you were "Doorknob" and had his picture. Now, your pic is a sheep. You should change it to a llama. – Justin May 4 '14 at 23:11
• What about 0-based vs 1-based indexing? Can we just use the indexing used by our language or do all submissions have to conform to one convention (which one)? – Martin Ender May 4 '14 at 23:37
• @Quincunx The sheep says '42' on it! – Cilan May 5 '14 at 0:34
• @TheWobbuffet way too many maths oriented ones :-/ (Matlab, Mathematica, Julia, I don't know about R)... also Lua and Smalltalk. The only one of those relevant to code golfing would be Mathematica though, but probably not for string manipulation tasks. – Martin Ender May 5 '14 at 0:44
• Do you just want the function that does it or the whole program? Do you want the input/output code as well? – mnsr May 5 '14 at 2:17

# CJam - 33

lel"llama"{1$#)_T+:T\@>}/;]___|=*  It gets the 1-based indexes (2 more bytes for 0-based) Explanation: l reads a line from the input (replace with q for whole input) el converts to lowercase "llama"{...}/ executes the block for each "llama" letter 1$ copies the current string
# finds the index of the letter
)_ increments and duplicates
T+:T adds T (initially 0), updates T and leaves it on the stack
\@ swaps items around, now we have current-T, index, string
> slices the string starting at the index
; pops the remaining string
] gathers the indexes in an array
At this point we have all the 1-based indexes; iff any letter was not found, the array will have duplicates.
___ makes 3 more copies of the array
| (with 2 array copies) removes duplicates
= compares, resulting in 0 if there were duplicates or 1 if not
* multiplies the array 0 or 1 times accordingly

# Perl, 52 bytes

The solution is provided as function that takes the string as argument and returns a list of positions.

• One-based positions, case-sensitive search, without newlines: 52 bytes

sub l{pop=~/(l).*?(l).*?(a).*?(m).*?(a)/;@+[1..$#+]}  The case-sensitive search returns an empty array in the example of the question, because after matching the first three letters the lowercase letter m is missing in the input text. • Support of newlines: + 1 byte = 53 bytes sub l{pop=~/(l).*?(l).*?(a).*?(m).*?(a)/s;@+[1..$#+]}


The text can now span several lines.

• Case-insensitive search: + 1 byte = 54 bytes

sub l{pop=~/(l).*?(l).*?(a).*?(m).*?(a)/si;@+[1..$#+]}  Now the example in the question reports a list of index positions, they are one-based numbers: [45 68 77 106 115]  • Zero-based positions: + 9 bytes = 63 bytes sub l{pop=~/(l).*?(l).*?(a).*?(m).*?(a)/si;map{$_-1}@+[1..$#+]}  Result for the example in the question: [44 67 76 105 114]  Ungolfed: The latter variant includes more or less the other variants. sub l { # pop() gets the last argument pop() =~ /(l).*?(l).*?(a).*?(m).*?(a)/si; # the letters inbetween are matched against ".*?", # the non-greedy variant of ".*". Thus ".*?" # matches only as few as possible characters. # The modifier /i controls the case-sensitivity # and means ignore case. Without the case matters. # Modifier /s treats the string as single line, # even if it contains newlines. map {$_-1 }   # subtract 1 for zero-based positions
@+[1..$#+] # Array @+ contains the end-positions of the last # submatches, and of the whole match in the first position. # Therefore the first value is sliced away. # @+ is available since Perl 5.6. } # test my @result = l(<<"END_STR"); Pie is good. I just ate a bunch of pies early this morning. Actually, it was closer to the afternoon. Mornings are good. END_STR print "[@result]\n";  • This also assumes that the input is ASCII, or at least not full Unicode. Unless Perl's regexes correctly respect grapheme boundaries these days (they certainly did not back when I had the misfortune of using it.) – Trejkaz May 5 '14 at 13:06 • @Trejkaz: Unicode does not matter at all here: (a) "llama" is ASCII and its letters does not collide with any non-ASCII Unicode character or its byte representation in UTF-8. (b) With multi-byte encodings in mind, the term "index" in the question would be underspecified. Index can relate to the character position or the byte (storage) position. (c) Supporting any encoding with characters positions would mean, that the encoding should be known and needs to be provided as additional argument. – Heiko Oberdiek May 5 '14 at 15:38 • Your first two solutions print [] and the third prints [ ] for me (the longer ones work correctly). I'm running "perl, v5.8.8 built for msys-64int". Do you have a bug, or does it work on a different version of perl? – Tim S. May 5 '14 at 17:48 • @TimS.: [] is correct for the first solution, M is not matched in a case-sensitive search. The question is quite unclear regarding case-sensitivity. – Heiko Oberdiek May 5 '14 at 17:52 • Ok, so [] is acceptable for the first two. But the first three solutions are still not working right for me: if you give it input that should return indexes, it returns [ ] – Tim S. May 5 '14 at 17:55 # sed, 299+1 Yes, sed can find a llama. No, sed can't do math. This is the longest answer so far, at 299+1 characters, because I had to teach sed to count. This answer requires a sed with extended regular expressions (sed -E or sed -r). I used OpenBSD sed(1). Input is one string per line. (Therefore, the string may not contain a newline.) Output is a line of numbers, or nothing. Usage (+1 character for -r): $ echo 'All arms on all shoulders may ache.' | sed -rf llama.sed
1 2 12 26 30


Source code (299 characters):

s/%/z/g
s/(.*)[Aa]/\1%/
s/(.*)[Mm](.*%)/\1%\2/
s/(.*)[Aa]((.*%){2})/\1%\2/
s/(.*)[Ll]((.*%){3})/\1%\2/
s/(.*)[Ll]((.*%){4})/\1%\2/
/(.*%){5}/!d
s/[^%]/z/g
:w
s/(z*)%/\10 z\1/
s/z*$// s/z0/1/ s/z1/2/ s/z2/3/ s/z3/4/ s/z4/5/ s/z5/6/ s/z6/7/ s/z7/8/ s/z8/9/ s/([0-9]z*)z9/z\10/g s/(z*)z9/1\10/ /[%z]/bw  The program first replaces the llama with five %. (All % in this program are literal.) The first command s/%/z/g changes any % to z in the input line. The next five commands find the llama, so All arms on all shoulders may ache. becomes A%% arms on %ll shoulders %ay %che. Because each .* is greedy, I always finds the llama on the right: llama llama would become llama %%%%%. If I can't get five %, then /(.*%){5}/!d deletes the input line and skips the next commands. s/[^%]/z/g changes every character but % to z. Then I enter a loop. s/(z*)%/\10 z\1/ changes the first % to 0, copies zero or more z from left to right, and adds one more z to right. This is so the number of z will equal the index. For example, zz%zzz%... becomes zz0 zzzzzzzz%... because the first % was at index 2, and the next % is at index 8. s/z*$// removes extra z from the end of the string.

The next eleven commands count z by removing each z and counting up from 0. It counts like zzz0, zz1, z2, 3. Also, 1zzzz9 becomes z1zzz0 (later 23), or zzzz9 becomes 1zzz0 (later 13). This loop continues until there are no more % or z.

• +1 for teaching sed to count. It is easier to teach a llama to count than sed. – Andreï Kostyrka Aug 31 '16 at 15:48

## Fortran - 154 148

Fortran sucks at golfing, but just to prove that parsing strings can be done in a math-based language, I did it:

function f result(r);integer::r(5),j=1;do i=1,len(s);if(s(i:i)==a(j:j).or.s(i:i)==b(j:j)) then;r(j)=i;j=j+1;endif;enddo;if(any(r==0))r=0;endfunction


I saved a few characters by eliminating the not-required f at the end of endfunction and used if(any(r==0)) instead of if(.not.all(r>0)).

This requires:

1. s to be the string with text
2. a to be the lower-case test (i.e., llama)
3. b to be the upper-case test (i.e., LLAMA)

The full, un-golfed program is

program find_llama
character(len=123) :: s = "Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good."
character(len=5) :: a="llama",b="LLAMA"

print *,f()
contains
function f result(r)
integer::r(5),j=1
do i=1,len(s)
if(s(i:i)==a(j:j).or.s(i:i)==b(j:j)) then
r(j)=i
j=j+1
endif
enddo
if(any(r==0)) r=0
end function
end program find_llama

• Modern Fortran is at least allowed on the pitch & putt areas. FORTRAN IV would still be playing crazy golf. – ClickRick May 5 '14 at 6:30
• @ClickRick: Fortran IV is something I have not learned. Not sure that I want to. Something about forced indentation and capitalization disturbs me. – Kyle Kanos May 5 '14 at 10:52

## C# - 119

Takes string, outputs array. Null if no llama in string.

int[]a(string s){var i=0;var o="llama".Select((x,y)=>i=s.IndexOf(x,y>0?i+1:0));return o.All(x=>x>=0)?o.ToArray():null;}

• +1 for x=>x>=0 – ClickRick May 5 '14 at 6:25
• I am impressed. Way smaller than any of my ideas for this one. I did find you could make it smaller by initializing i to -1 and putting the .ToArray() on the .Select statement, like so int[]a(string s){var i=-1;var o="llama".Select(x=>i=s.IndexOf(x,i+1)).ToArray();return o.All(x=>x>=0)?o:null;} – Grax32 Jul 31 '14 at 15:24

# Ruby, 5665 63

Edit: +9 characters so that it is case-insensitive.

Defines a function (lambda, technically) f.

f=->s{i=0;'LLAMA'.chars.map{|c|i=s.upcase.index(c,i+1)||break}}


Returns nil if there is no llama. If it has to be [] (empty array), then just add ||[] before the last } for a total of 4 extra characters.

innerLlama = -> str{
index = 0;
str.downcase!
arr = 'llama'.each_char.map{|char|
index = str.index(char, index + 1)
break unless index
}
# uncomment this line for empty array on failure
#arr || []
}

• I apologize for editing my question after some time, but I just added that the array, if no llama, can be nil,null,empty, or undefined. – Cilan May 5 '14 at 0:41
• So you did it with a llambda? – Mason Wheeler May 5 '14 at 3:31
• @Doorknob would be two bytes shorter by using upcase instead of downcase no? – dstarh May 5 '14 at 14:24
• @dstarh Yep, thanks – Doorknob May 5 '14 at 17:10
• Think you can get case-insensitivity a byte cheaper by doing index(/#{c}/i instead of upcase. – histocrat May 7 '14 at 15:10

# C - 53

Compile with:

gcc -D L=\"llama\" -D W=\"Lie\ is\ good.\ \ I\ just\ ate\ a\ bunch\ of\ pies\ early\ this\ morning.\ \ Actually,\ it\ was\ closer\ to\ the\ afternoon.\ \ Mornings\ are\ good.\"


I tested this compile command with cygwin's gcc. Other environments might handle spaces, and other special characters differently.

The 0-based result is stored into array r. Its contents are undefined if there is no llama in the string.

• Case-sensitive (53)

i,m,r[5];main(){for(;W[i];i++)W[i]==L[m]?r[m++]=i:i;}

• Case-insensitive (58)

i,m,r[5];main(){for(;W[i];i++)(W[i]|96)==L[m]?r[m++]=i:i;}

# JavaScript (ECMAScript 6) - 68 Characters

(/((((.*l).*l).*a).*m).*a/.exec(s)||[]).map(x=>x.length-1).reverse()


Assumes that the string to test is in the variable s. If you want to turn it into a function then prepend f=s=> (for an additional 5 characters).

Outputs:

[]


Case Insensitive - 69 Characters

(/((((.*l).*l).*a).*m).*a/i.exec(s)||[]).map(x=>x.length-1).reverse()


Outputs:

[68, 80, 93, 105, 114]


Case Insensitive & First Match - 74 Characters

(/((((.*?l).*?l).*?a).*?m).*?a/i.exec(s)||[]).map(x=>x.length-1).reverse()


Outputs:

[44, 67, 76, 105, 114]


# Python, 100

I am the worst golfer ever. :P

Thanks to @xnor for shaving off 6 bytes.

g,n,o='llama',0,[]
for i in s:
if g:exec("o+=[n];g=g[1:];"*(i.lower()==g[0])+"n+=1")
o*=len(o)>4


o contains the array after.

EDIT: Fixed.

EDIT 2: len(g) to g, o==5 to o>4 as per @xnor's suggestions.

EDIT 3: @WolframH fixed it.

• o*=(len(o)==5) is excellent. It's horrible, but I love it! – kevinsa5 May 5 '14 at 5:30
• I don't think the outer parentheses on that line are necessary. You could save two characters by removing them. – user2357112 supports Monica May 5 '14 at 6:46
• @user2357112 On that second last line? I'll remove 'em. – cjfaure May 5 '14 at 8:59
• I assume s is the input string, right? Shouldn't then s.lower be i.lower? However, that doe – Reinstate Monica May 5 '14 at 19:56
• @WolframH ah, yes, will fix tomorrow. – cjfaure May 5 '14 at 19:59

## Python 71

Assumes input in s. Output in o.

F=s.lower().find
o=F('l'),
for c in'lama':o+=F(c,o[-1]+1),
o*=min(o)>=0


Edit: Changed from lists to tuples to save 2 bytes.

• Multiplying lists by booleans is fun, isn't it? ;D – cjfaure May 6 '14 at 6:10
• I like how you dodge the problem of o needing to start nonempty to take o[-1]. Maybe it's shorter though to just start o as [-1] and later do o=o[1:]? Annoyingly, the initial -1 trips up checking if o contains -1. – xnor May 8 '14 at 7:24
• @xnor: I don't think the -1-Idea can be made to work. At least, I didn't succeed :-( However, I changed lists to tuples to save 2 bytes. :-) – Reinstate Monica May 12 '14 at 18:11

# Python 100

import re
x=input()
print[re.search(r"l.*?(l).*?(a).*?(m).*?(a)",x,re.I).start(i) for i in range(5)]


Sample:

in  = Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good.
out = [44, 67, 76, 105, 114]
in[out] = ['l', 'l', 'a', 'M', 'a']


import Data.Char
l i(a:as)t@(b:bs)|a==b=i:l(i+1)as bs|True=l(i+1)as t
l _ _ _=[]
r s=l 0(map toUpper s)"LLAMA"


Ungolfed:

import Data.Char

llama :: Int -> String -> String -> [Int]
llama i (a:as) t@(b:bs)
| a==b      = i : llama (i+1) as bs
| otherwise = llama (i+1) as t
llama _ _ _ = []

runme :: String -> [Int]
runme s = llama 0 (map toUpper s) "LLAMA"


Example:

*Main> r "Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good."
[44,67,76,105,114]


## Matlab, 61 96

Searches the string and replaces everything up to each match with gibberish before searching for next character. Will leave s undefined if an the word does not occur.

t='llama';for q=1:5;s(q)=min(regexpi(z,t(q))),z(1:s(q))=0;end


Note that the charcount could be reduced if case sensitivity is allowed.

Previous versions

 try;t='llama';for q=1:length(t);s(q)=find(lower(z)==t(q),1);z(1:s(q))=ones(1,s(q));end;catch;end


Searches the string and replaces everything up to each match with gibberish before searching for next character. Error handling (try-catch-end) could maybe be dropped, then the program would crash (but s would be undefined as required) if llama not found.

Implementation:

>> z='Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good.';
>> try;t='llama';for q=1:length(t);s(q)=find(lower(z)==t(q),1);z(1:s(q))=ones(1,s(q));end;catch;end
>> s
s =

45    68    77   106   115


Without error handling:

t='llama';for q=1:length(t);s(q)=find(lower(z)==t(q),1);z(1:s(q))=ones(1,s(q));end

• Like the idea, have reduced charcount a bit. – Dennis Jaheruddin May 6 '14 at 12:15

Language Java

 final int[] wordIndexInSentence(String sentence, String word)
{
final int[] returnArr = new int[word.length()];
int fromIndex = 0;
word = word.toUpperCase();
sentence = sentence.toUpperCase();
for (int i = 0; i < word.length(); i++)
{
final char c = word.charAt(i);
returnArr[i] = sentence.indexOf(c, fromIndex);
fromIndex = returnArr[i] > 0 ? returnArr[i] + 1 : fromIndex;
}
return returnArr;
}


# Python (70)

r=[];c=-1
for x in'llama':c=s.lower().find(x,c+1);r+=[c]
r*=1-(-1in r)


We search of each character in 'llama' in turn, starting after the location of the previously-found character. If no character is found, c becomes the default value of -1, in which case the last line turns r into the empty list.

Edit: Found out that str.find(s,...) can be invoked as s.find(...), saving 4 characters.

# OpenEuphoria, 147128

I have two examples. First, the shortest:

object t=and_bits(gets(0),#DF),L="LLAMA",i=0,X={}for j=1 to 5 do
i=find(L[j],t,i+1)X&=i
end for
if find(0,X) then X={} end if?X


I can get it down to 126 characters if I use "or" instead of "and" like the C version does up above. However, this also matches the string ''!-! as llama. Uncommon, but still a possible error.

object t=or_bits(gets(0),96),L="llama",i=0,X={}for j=1 to 5 do
i=find(L[j],t,i+1)X&=i
end for
if find(0,X) then X={} end if?X


And then the version using regular expressions:

include std/regex.e
include std/sequence.e
include std/utils.e
object X=regex:find(new("(?i)(l).*?(l).*?(a).*?(m).*?(a)"),gets(0))
? iff(atom(X),{},vslice(X[2..6],2))


Both take input from STDIN and post to STDOUT.

EDIT: Shorter regex example:

include std/regex.e
include std/sequence.e
object X=regex:find(new("(?i)(l).*?(l).*?(a).*?(m).*?(a)"),gets(0))
if atom(X)then?{}else?vslice(X[2..6],2)end if

• Is it possible to save a few by building the regex with split/join or explode/implode, or does OpenEuphoria not have short versions of those? – Peter Taylor May 8 '14 at 9:09
• OpenEuphoria can do split/join with strings of characters, but I don't see a way to do it in a shorter manner. I'm not very good with regular expressions; the regex used here was "inspired" (shamelessly stolen) from one of the other examples on this page. – TinSoldier May 8 '14 at 13:44

# Powershell - 121 85

I'm still practicing with Powershell, expect this could be improved

$s contains the string, result is in array$a

Original version

$a=@();$w="llama";$n=$c=0;foreach ($i in$s.tochararray()) {if ($i -eq$w[$n]) {$a+=$c;$n+=1} $c+=1};$a*=$a.length -gt 4  Ungolfed $a=@()
$w="llama"$n=$c=0 foreach ($i in $s.tochararray()) { if ($i -eq $w[$n]) {
$a+=$c
$n+=1 }$c+=1
}
$a*=$a.length -gt 4


New version, with massive thanks to @goric

$a=@();$n=$c=0;[char[]]$s|%{if($_-eq"llama"[$n]){$a+=$c;$n++}$c++};$a*=$a.length-gt4

• You can remove a lot of spaces in there to shorten things up to 112: $a=@();$w="llama";$n=$c=0;foreach($i in$s.tochararray()){if($i-eq$w[$n]){$a+=$c;$n+=1}$c+=1};$a*=$a.length-gt4 – goric May 9 '14 at 19:05 • Also, you can replace foreach($i in $s.tochararray()) with [char[]]$s|%, as long as you change the subsequent $i to a $_. That shaves it down to 93: $a=@();$w="llama";$n=$c=0;[char[]]$s|%{if($_-eq$w[$n]){$a+=$c;$n+=1}$c+=1};$a*=$a.length-gt4 – goric May 9 '14 at 19:08
• Save 5 more chars by removing the $w variable altogether, since its only used once. Just inline it into the if: if($i-eq"llama"[$n]) – goric May 9 '14 at 19:14 • ..and, of course, replace your +=1s with ++s – goric May 9 '14 at 19:25 # PHP no PHP answer yet? I think a language heavily string-oriented can beat at least a math-based one function x($s){$i=$j=0;$r=str_split('llama');$s=strtolower($s);while($i<strlen($s)){if($s[$i]==$r[$j]){$r[$j]=$i;$j++;if($j>4)return$r;}$i++;}return[];}



152 against fortran 154, job done :P

ungolfed

function x($s){$i=$j=0;$r=str_split('llama');
$s=strtolower($s);
while($i<strlen($s)){
if ($s[$i]==$r[$j]){
$r[$j]=$i;$j++;
if($j>4) return$r;
}
\$i++;
}
return[];
}


if the caller always passes a lowercase string, it lowers to 137

• You need to add <? at the beginning of your code to make it valid. Sorry... – avall May 8 '14 at 7:40

# JavaScript, 122 115

function(s,b){z=[];for(i=0;i<5;i++){z.push(b=s.toLowerCase().indexOf("llama"[i],++b))};return z.indexOf(-1)<0?z:[]}


Defines a function that takes a string as its only argument (second arg is a cheap var) and returns either an empty array or a 5-element array.

Drops to 108 if I take the input on a single char variable (s) and leave the output in another (b):

var b=((z="llama".split('').map(function(a){return (b=s.toLowerCase().indexOf(a,++b))})).indexOf(-1)<0?z:[])


Edit: Swapped out map for for loop.

• ECMAScript 6 version (81 characters) - b=(z=[].map.call("llama",a=>b=s.toLowerCase().indexOf(a,++b))).indexOf(-1)<0?z:[] – MT0 May 5 '14 at 22:31

# Rebol, 97

f: func[s][a: copy[]foreach n"llama"[if none? s: find s n[return[]]append a index? s s: next s]a]


Usage example in Rebol console:

>> f "Pie is good.  I just ate a bunch of pies early this morning.  Actually, it was closer to the afternoon.  Mornings are good."
== [45 68 77 106 115]

>> f "nearly llami"
== []

>> f "Llama"
== [1 2 3 4 5]

>> f reverse "llama"
== []


Rebol uses 1-based indexing. Returns empty list [] if no llama sequence found (case insensitive).

Ungolfed:

f: func [s] [
a: copy []
foreach n "llama" [
if none? s: find s n [return []]
append a index? s
s: next s
]
a
]


# APL, 47

+\↑⊃{a s←⍵⋄~⍺∊s:⍬⍬⋄a,←n←s⍳⍺⋄a(n↓s)}/'amall',⊂⍬⍞


Not the shortest code, but quite warped, in an APL way.

Explanation

'amall',⊂⍬⍞ Make an array of 6 elements: the letters 'amall' and a subarray of 2 elements, themselves subarrays: the empty array and a line of characters read from input.

{...}/... Reduce (right-fold) the 6-element array using the provided function.

a s←⍵ Decompose the right argument into the array of indices and the remaining substring (initially the empty array and the full string.)

~⍺∊s:⍬⍬ If the substring does not contain the next letter ⍺ stop the computation and return the empty array.

a,←n←s⍳⍺ Otherwise, find its position, call it n, and append it to the array of indices.

a(n↓s) Make and return an array of 2 elements: the extended array of indices and the remaining substring.

+\↑⊃... Unpack the output of the folding, take the first element (the array of indices) and scan it with addition, to turn relative offsets into absolute ones.

Examples

      +\↑⊃{a s←⍵⋄~⍺∊s:⍬⍬⋄a,←n←s⍳⍺⋄a(n↓s)}/'amall',⊂⍬⍞
All cats meow aloud.
2 3 6 10 15


      +\↑⊃{a s←⍵⋄~⍺∊s:⍬⍬⋄a,←n←s⍳⍺⋄a(n↓s)}/'amall',⊂⍬⍞

f(s)=(m=match(r"(?i)(l).*?(l).*?(a).*?(m).*?(a)",s);m==nothing?m:m.offsets)