Look And Say
March 15, 2011
This exercise is a celebration of the Standard Prelude. Function look-and-say returns the next number in the sequence:
(define (look-and-say n)
(define (flip x) (cons (cdr x) (car x)))
(undigits (flatten (map flip (uniq-c = (digits n))))))
If that looks tricky, it helps to break it down in stages. For instance, to compute the successor of 1211, working from the inside out:
digits n: (1 2 1 1)
uniq-c =: ((1 . 1) (2 . 1) (1 . 2))
map flip: ((1 . 1) (1 . 2) (2 . 1))
flatten: (1 1 1 2 2 1)
undigits: 111221
Then it is easy to compute the first n terms of the sequence:
(define (look-and-say-sequence n)
(iterate n look-and-say 1))
Here’s the output:
> (look-and-say-sequence 10)
(1 11 21 1211 111221 312211 13112221 1113213211
31131211131221 13211311123113112211)
We used iterate, flatten, uniq-c, digits and undigits from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/XC60i6ec.
Here’s a quick solution in ghci:
Prelude> import Data.List
Prelude Data.List> let n = concatMap (\x -> (show $ length x) ++ [head x]) . group
Prelude Data.List> take 10 $ iterate n “1”
[“1″,”11″,”21″,”1211″,”111221″,”312211″,”13112221″,”1113213211″,”31131211131221″,”13211311123113112211”]
My Haskell solution (see http://bonsaicode.wordpress.com/2011/03/15/programming-praxis-look-and-say/ for a version with comments):
import Data.List lookAndSay :: Integer -> [Integer] lookAndSay = iterate (read . f . group . show) where f = (>>= \x -> show (length x) ++ take 1 x)[…] today’s Programming Praxis exercise, our task is to generate the Look and Say sequence (1, 11, 21, 1211, […]
A Python solution:
import itertools def lookandsay(number): return "".join(str(sum(1 for x in g)) + k for k,g in itertools.groupby(number)) seq = ['1'] for _ in xrange(10): seq.append(lookandsay(seq[-1])) print seqUsing the
groupby()function from Python’s itertools module:from itertools import groupby def next_iter(s): return ''.join([str(len(list(g))) + k for k, g in groupby(s)]) if __name__ == "__main__": s = '1' for _ in xrange(10): print s s = next_iter(s)Looks like Dave beat me to it :-) I should have refreshed the page before posting.
Clojure solution:
(defn lookandsay [s]
(mapcat (juxt count first)
(partition-by identity s)))
(take 10 (iterate lookandsay [1]))
A listless solution, integer to integer, in Scheme.
(define (say-next n) (let loop ((m (quotient n 10)) (digit (remainder n 10)) (count 1) (result 0) (length 1)) (if (= m digit 0) result (let ((m1 (quotient m 10)) (digit1 (remainder m 10))) (if (= digit1 digit) (loop m1 digit (+ count 1) result length) (loop m1 digit1 1 (+ (* count 10 length) (* digit length) result) (* length 100)))))))Output using iterate from that Standard Prelude.
Because Sloane’s is a catalogue of integer sequences, I wrote a generator that return successive integers of the sequence.
My first version is basically the same as Webb’s and Graham’s above, so I also did a second version using the regular expression library.
I was somewhat suprised that the second version appears to be slightly faster, based on using the timeit module.
# version 1: Uses itertools.groupby(). from itertools import groupby def look_and_say1(n): '''generate 'look and say' sequence. >>> list(islice(look_and_say1(13),5)) [13, 1113, 3113, 132113, 1113122113] ''' s = list(str(n)) while True: yield int(''.join(s)) s = [d for k,g in groupby(s) for d in (str(len(list(g))), k)] # version 2: Uses re.sub(). import re def look_and_say2(n): '''generate 'look and say' sequence. >>> list(islice(look_and_say2(13),5)) [13, 1113, 3113, 132113, 1113122113] ''' def say(mo): g = mo.group() return '{}{}'.format(len(g),g[0]) s = str(n) pat = re.compile(r'([1-9])\1*') while True: yield int(s) s = pat.sub(say ,s) #testing from itertools import islice, izip def test(limit=10): '''compares output of both generators. >>> test() Ok ''' for n in range(1,9): for s,t in islice(izip(look_and_say1(n),look_and_say2(n)), limit): if s != t: print s, '!=', t return print 'Ok' if __name__ == "__main__": import doctest doctest.testmod()My try in REXX
txt = '1' MAXLEN = 20 say lookandsay(txt) exit lookandsay: procedure expose MAXLEN parse arg seq outseq = seq do while length(seq) < MAXLEN new = '' prv = '' cnt = 0 do x = 1 to length(seq) n = substr(seq, x, 1) if n \= prv then do if cnt > 0 then new = new||cnt||prv prv = n cnt = 0 end if length(new) > MAXLEN then leave cnt = cnt + 1 end if cnt > 0 then new = new||cnt||prv outseq = outseq new seq = new end return outseq[…] autre petit exercice de Programming Praxis, programmer la suite Look and Say. Ce n’est pas très difficile : import Data.List import […]
My Haskell solution
import Data.List import Data.Digits lookAndSay :: [Integer] lookAndSay = map (unDigits 10) $ iterate next [1] where next = concatMap count . group count lst@(x:xs) = [fromIntegral (length lst), x]in scala:
def lookAndSay(previous:List[Int]) : Stream[List[Int]] = {
def next(num : List[Int]) : List[Int] = num match {
case Nil => Nil
case head :: Nil => 1 :: head :: Nil
case head :: tail => {
val size = (num takeWhile{_ == head}).size
List(size, head) ::: next(num.drop(size))
}
}
val x = next(previous)
x #:: lookAndSay(x)
}
lookAndSay(1::Nil) take 10 foreach (println _)
Here’s a JS solution. I’ve only been programming for about a year, mostly JS and PHP. Going to attempt a PHP version next, then subsequently, ajax-ify it.
Look and Say Sequence
var start = false;
var result;
function lookSay(int, repeat) {
for (t=1; t<=repeat; t++) {
if (!start) {
start = int;
result = start+"”;
}
newNumber = “”;
digit = start.charAt(0);
count = 1;
for (var i = 1; i < start.length; i++) {
if (digit == start.charAt(i)) {
count++;
}
else {
newNumber = newNumber + count + digit;
digit = start.charAt(i);
count = 1;
}
}
start = newNumber + count + digit;
if (t == repeat) {
result+=start;
document.getElementById('result').innerHTML=result;
start = false;
result = '';
}
else {
result +=start+"”;
}
}
}
function returnResult() {
s = document.getElementById(‘start’).value;
r = document.getElementById(‘repeat’).value;
lookSay(s, r);
}
Start Integer:
Repeat Amount:
Submit
A Scheme solution using lists is:
; Copyright (C) 2011 Toby Thain, toby@telegraphics.com.au (define (look-and-say terms) (define (next-value lst) (let count-digit ((this-digit (car lst)) (count 1) (rest (cdr lst))) (cond ((null? rest) (list count this-digit)) ((eq? this-digit (car rest)) (count-digit this-digit (+ count 1) (cdr rest))) (else (append (list count this-digit) (count-digit (car rest) 1 (cdr rest))))))) (let step ((value '(1)) (n terms)) (if (zero? n) '() (cons value (step (next-value value) (- n 1))))))A ruby version:
sloane = [1]
puts sloane.inspect
8.times.each do |iteration|
new_sloane = []
rep_digit = 1
last_sum = sloane.inject(0) do |sum, digit|
next sum + 1 if digit == rep_digit
new_sloane << rep_digit
new_sloane << sum
rep_digit = digit
1
end
new_sloane << rep_digit
new_sloane << last_sum
puts sloane.replace(new_sloane).reverse.inspect
end
[/sourcecode]
(define (build-next items) (define (build-next-iter items number freq next) (cond ((and (pair? items) (equal? (car items) number)) (build-next-iter (cdr items) number (+ freq 1) next)) ((and (pair? items) (not (equal? (car items) number))) (build-next-iter (cdr items) (car items) 1 (cons next (cons freq number)))) (else (cons next (cons freq number))))) (flatten (build-next-iter items (car items) 0 '()))) (define (look-and-say-from s) (cons-stream s (look-and-say-from (build-next s)))) (define look-and-say-stream (look-and-say-from (cons 1'()))) (stream-head look-and-say-stream 8)Mine in F#
let look_and_say (s:string) = let next = s.ToCharArray() |> List.ofArray |> List.fold (fun acc x -> match acc with | [] -> [(x, 1)] | (a,b)::t -> match compare x a with | 0 -> (a,b+1)::t | _ -> (x,1)::acc ) [] |> List.rev |> List.map (fun (a,b) -> (string b) + (string a)) |> Seq.ofList |> String.concat "" Some(s, next) let Sloan = Seq.unfold look_and_say "1"Here is a solution in Factor:
http://re-factor.blogspot.com/2011/03/look-and-say.html
For the curious, Factor looks like this:
: look-and-say ( n — n’ )
number>string [ = ] monotonic-split [
[ length ] [ first ] bi "%d%c" sprintf
] map concat string>number ;
is anybody have solution in c plz upload here
Rohit, check my website link here for a version in C. Please note that it is NOT written for clarity. But it is in C, and it works. Increase the ‘M’ constant if you want more numbers in the series; for example, 1000000 gives you the first 49 terms.