PythonとRubyでパスカルの三角形ワンライナー
rubyco(るびこ)の日記 - 呼び出し側のアスタリスクを読んで、「あ、そうか、それを使えば頭から二つずつ取ることができるか」とGame Scripting Memo - 続・パスカルの三角形のことを思い出しました。
>>> def get2(f, a, b, *rest): result = [f(a, b)] if rest: result += get2(f, *rest) return result >>> from operator import add >>> def dup(aList): return reduce(add, [[v, v] for v in aList]) >>> dup([1,2,3]) [1, 1, 2, 2, 3, 3] >>> def sandwich(bread, meat): return [bread] + meat + [bread] >>> sandwich(0, dup([1, 2, 1])) [0, 1, 1, 2, 2, 1, 1, 0] >>> get2(add, *sandwich(0, dup([1, 2, 1]))) [1, 3, 3, 1]
とりあえずワンライナーにするために手を加えて…
>>> def get2(f, a, b, *rest): return rest and [f(a, b)] + get2apply(f, *rest) or [f(a, b)] >>> def next(xs): return get2(add, *sandwich(0, dup(xs))) >>> def next(xs): return get2(add, *sandwich(0, reduce(add, [[v, v] for v in xs]))) >>> def next(xs): return get2(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0]) >>> next([1]) [1, 1] >>> next(_) [1, 2, 1] >>> next(_) [1, 3, 3, 1] >>> next(_) [1, 4, 6, 4, 1] >>> def next(xs): g = lambda f, a, b, *rest: rest and [f(a, b)] + g(f, *rest) or [f(a, b)] return g(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0]) >>> def next(xs): g = lambda f, a, b, *rest: rest and [f(a, b)] + g(f, *rest) or [f(a, b)]; return g(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0]) >>> next([1]) [1, 1]
いちおうワンライナーになりました。
>>> lambda xs: (lambda g: (lambda *args: g(g, *args)))(lambda g, f, a, b, *rest: rest and [f(a, b)] + g(g, f, *rest) or [f(a, b)])(add, *[0] + reduce(add, [[v, v] for v in xs]) + [0]) <function <lambda> at 0x0146BC70> >>> _([1, 2, 1]) [1, 3, 3, 1]
これで文を使わない1つの式になりました。
__ Rubyは詳しくないので…ええっと、Proc.new{|x| x + 1}で無名関数のようなものができて、callでそれを呼べるんですかね。あ、 proc {...} で Proc.new{...} と同じだそうです。
$g = proc {|a, b, *rest|
if rest.size == 1
[a + b, rest[0]]
else
[a + b] + $g.call(*rest)
end
}
(0..9).inject([1]){|xs, item|
proc{|x| p x; x}.call(
$g.call(0, *xs.map{|v| [v, v]}.flatten)
)
}
三角形の頭が表示されないですけど一応動きました。
(0..9).inject([]){|xs, i|
proc{|x| p x; x}.call(
if i == 0
[1]
else
proc{|xs|
proc {|g|
proc {|*args|
g.call(g, *args)
}
}.call(
proc {|g, a, b, *rest|
if rest.size == 1
[a + b, rest[0]]
else
[a + b] + g.call(g, *rest)
end
}
).call(
0, *xs.map{|v| [v, v]}.flatten
)
}.call(xs)
end
)
}
できました。改行を取り除くのはお任せします。