Flipping Pancakes
April 7, 2009
Pity the poor waiter:
The chef in our place is sloppy, and when he prepares a stack of pancakes they come out all different sizes. Therefore, when I deliver them to a customer, on the way to the table I rearrange them (so that the smallest winds up on top, and so on, down to the largest at the bottom) by grabbing several from the top and flipping them over, repeating this (varying the number I flip) as many times as necessary.
Your task is to write a function that sorts a list of unique positive integers into ascending order using the pancake-flipping algorithm. When you are finished, you can read or run a suggested solution, or post your solution or discuss the exercise in the comments below.
This Haskell solution does some unnecessary flips if the bottom of the current subset is already in the correct position, but then again if you want efficiency just do a merge- or quicksort :)
Man that Haskell solution is compact. It’s gorgeous. Too bad my Haskell is so rusty that it doesn’t mean anything to me.
Haskell, the twitter of programming languages…
; Solution using fold
#lang scheme
(require srfi/1)
(define (flip n xs)
(let-values ([(top bottom) (split-at xs n)])
(append (reverse top) bottom)))
(define (find-max n xs)
(let ([m (apply max (take xs n))])
(list-index (λ (x) (= x m)) xs)))
(define (pancake xs)
(fold (λ (n xs) (flip n (flip (+ (find-max n xs) 1) xs)))
xs
(reverse (iota (length xs) 1))))
(pancake ‘(7 2 9 4 6 11 1 3 8 5 13))
; Solution without fold.
#lang scheme
(require srfi/1)
(define (flip n xs)
(let-values ([(top bottom) (split-at xs n)])
(append (reverse top) bottom)))
(define (find-max n xs)
(let ([m (apply max (take xs n))])
(list-index (λ (x) (= x m)) xs)))
(define (nest f n base)
(if (= n 0)
base
(nest f (- n 1) (f n base))))
(define (pancake xs)
(nest (λ (n xs) (flip n (flip (+ (find-max n xs) 1) xs)))
(length xs)
xs))
(pancake ‘(7 2 9 4 6 11 1 3 8 5 10 ))
Ben,
It’s not too hard to define Scheme functions so they resemble the curry-and-compose style of Haskell. I just uploaded a small library of higher-order functions to the Standard Prelude, including compose and define-curried; fold-right is already there. That’s most of what you need to replicate the Haskell solution.
I notice that the prelude contains this definition:
(define (second x y) y)
There is a strong tradition however to let second be:
(define (second xs) (list-ref xs 1))
I am not sure what the traditional name for
the projection is, but perhaps project2 ?
I think an even older and stronger tradition is to spell your second “cadr”. I just looked; cadr appears on page 13 of the Lisp 1.5 Programmer’s Manual, in the definition of apply.
In modern times second is used instead of cadr to stress that one is working with lists. The operation cadr is used for trees built using conses.
Both in SRFI 1 and the Common Lisp HyperSpec second is used to access the second element of a list.
here’s my python:
fixed to work with duplicates:
oops,
step += 2
shouldn’t be therehttps://github.com/ftt/programming-praxis/blob/master/20090407-flipping-pancakes/flip.py