Alphabetic Fannkuch

14

1

Fannkuch is a classic benchmark program. The name comes from the German "Pfannkuchen"- pancakes- for the algorithm's resemblance to flipping stacks of pancakes. A Fannkuch sequence of numbers is formed as follows:

Take a permutation of {1.....n}, for example: {4,2,1,5,3}. Take the first element, here 4, and reverse the order of the first 4 elements: {5,1,2,4,3}. Repeat this until the first element is a 1, so flipping won't change anything more: {3,4,2,1,5}, {2,4,3,1,5}, {4,2,3,1,5}, {1,3,2,4,5}

You are to write a program or function which calculates a Fannkuch-like sequence for strings of alphabetic characters. Instead of using numbers to indicate how many elements of the list should be flipped each time, the position of a letter in the alphabet should be used. For example, a leading c would indicate that you should reverse the order of the first 3 elements, while a leading a indicates that the sequence is complete.

Input

Input will be provided as a string via stdin or as a function argument. The string will contain between 1 and 26 distinct lowercase letters. Strings will not contain letters whose equivalent index would cause the Fannkuch algorithm to flip more elements than exist.

Output

Programs or functions should return or print to stdout the sequence of terms produced by applying the Fannkuch algorithm until a leading a is encountered, including the initial string. For example, if the input is bca, you might print:

bca
cba
abc

Printed results can use any reasonable separator- commas, newlines, etc. Any choice of whitespace is acceptable.

As another example, if your input is eabdc you might return:

("eabdc"
 "cdbae"
 "bdcae"
 "dbcae"
 "acbde")

Rules and Scoring

This is - the shortest program wins. Standard Loopholes are disallowed.

JohnE

Posted 2015-07-26T15:40:34.573

Reputation: 4 632

Answers

11

Pyth, 16 bytes

.u+_<NJhxGhN>NJz

Demonstration.

The "repeat until it stops changing" feature of Pyth's reduce functions is really handy here. This is used with .u, the cumulative reduce function, to output all results. The body of the reduce is as naive as can be, but I couldn't find anything better.

isaacg

Posted 2015-07-26T15:40:34.573

Reputation: 39 268

5

T-SQL, 213 bytes

Of course being SQL it's really large, but it was interesting to do. Created as an inline table function using a recursive CTE query.

CREATE FUNCTION F(@ CHAR(26))RETURNS TABLE RETURN WITH R AS(SELECT @ S UNION ALL SELECT CAST(STUFF(S,1,ASCII(LEFT(S,1))-96,REVERSE(LEFT(S,ASCII(LEFT(S,1))-96)))AS CHAR(26))FROM R WHERE LEFT(S,1)<>'a')SELECT*FROM R

Expanded

CREATE FUNCTION F(@ CHAR(26))
RETURNS TABLE 
RETURN WITH R AS(
    SELECT @ S            -- Initial string as an anchor for the recursion
    UNION ALL 
    SELECT CAST(
        STUFF(                                    -- Stuff into 
            S,                                    -- string S
            1,                                    -- from position 1
            ASCII(LEFT(S,1))-96,                  -- to index value of first char
            REVERSE(LEFT(S,ASCII(LEFT(S,1))-96))  -- the reverse of the index first chars
            )
        AS CHAR(26))
    FROM R 
    WHERE LEFT(S,1)<>'a'  -- recurse until first char is a
)SELECT*FROM R

Used as follows

SELECT * FROM F('eabdc')
S
--------------------------
eabdc                     
cdbae                     
bdcae                     
dbcae                     
acbde                     

(5 row(s) affected)

MickyT

Posted 2015-07-26T15:40:34.573

Reputation: 11 735

4

CJam, 22 bytes

This is an anonymous function which takes a string on stack and returns a list of string on the stack.

{_,{_0='`-/(W%\+s_}*]}

Try it online here

Optimizer

Posted 2015-07-26T15:40:34.573

Reputation: 25 836

3

Python 2, 59 bytes

def p(l):
 print l;o=ord(l[0])-97
 if o:p(l[o::-1]+l[o+1:])

I guess this is a rather straightforward answer. Uses recursion and Python's slice syntax. Call as: p('eabdc').

mathmandan

Posted 2015-07-26T15:40:34.573

Reputation: 943

3

SAS, 131 bytes

sub a(s$);outargs s;put s;do while(b ne 1);b=rank(char(s,1))-96;substr(s,1,b)=reverse(substr(s,1,b));if b>1 then put s;end;endsub;

An FCMP call routine. Nongolfed below (with an extra check I highly recommend as SAS crashes if an FCMP routine enters an infinite loop).


options cmplib=work.funcs;
proc fcmp outlib=work.funcs.funcs;
  sub a(s$);
    outargs s;
    put s=;
    do while (b ne 1 and z<1e5);
        b=rank(char(s,1))-96;
        substr(s,1,b) = reverse(substr(s,1,b));
        if b>1 then put s=;
        z+1;
    end;
  endsub;
quit;

Joe

Posted 2015-07-26T15:40:34.573

Reputation: 283

Nice work. We don't get much proc fcmp around here. – Alex A. – 2015-07-27T20:24:31.393

2

Haskell, 78 bytes

f l@(h:_)|h=='a'=[l]|1<2=l:f(reverse(take d l)++drop d l)where d=fromEnum h-96

Usage: f "eabdc" -> ["eabdc","cdbae","bdcae","dbcae","acbde"].

nimi

Posted 2015-07-26T15:40:34.573

Reputation: 34 639

consider using splitAt -- you can get it down to 71 bytes! – MtnViewMark – 2015-07-27T05:58:57.480

@MtnViewMark well i seem to have the exact same algorithm, down to 68 bytes – proud haskeller – 2015-07-27T08:48:36.143

2

K5, 21 bytes

{(|v#x),(v:*x-96)_x}\

Saved 5 bytes thanks to @JohnE and another byte by rearranging an expression.

For the first time on earth, I think K has beaten CJam!

27-byte version

(~97=*){(|v#x),(v:-96+*x)_x}\

kirbyfan64sos

Posted 2015-07-26T15:40:34.573

Reputation: 8 730

You can make this quite a bit shorter if you use the fixed-point form of "scan". – JohnE – 2015-07-27T20:32:02.987

@JohnE Thanks! I didn't realize that, when the first letter is an a, the string won't change. – kirbyfan64sos – 2015-07-27T20:52:58.093

0

Haskell, 68

f l@(x:_)|x<'b'=[l]|(x,y)<-splitAt(fromEnum x-96)l=l:f(reverse x++y)

Any more complicated tactic I thought of took more bytes.

proud haskeller

Posted 2015-07-26T15:40:34.573

Reputation: 5 866