开发者

How can I create a tuple where each of the members are compared by an expression?

Well, here is the thing:

I have the following Haskell code, this one:

[ (a, b, c) | c <- [1..10], b <- [1..10], a <- [1..10], a ^ 2 + b ^ 2 == c ^ 2 ]

Which will returns

[(4,3,5),(3,4,5),(8,6,10),(6,8,10)]

For those who aren't familiar with this, I'll explain:

  • It returns a tuple (a,b,c), where each of these "definitions" (a,b,c) receive a list (1 up to 10) and his members are compared by the a ^ 2 + b ^ 2 == c ^ 2 ? expression (each member).

How can I do the same (one line i开发者_StackOverflow社区f possible) in Python/Ruby?

P.S.: they are compared in lexicographical order.


It's possible in Python with one long line and with no import. Python's list comprehensions can be used with multiple variables:

>>> [ (a, b, c) for c in range(1, 11) for b in range(1, 11) for a in range(1, 11) if a*a + b*b == c*c ]
[(4, 3, 5), (3, 4, 5), (8, 6, 10), (6, 8, 10)]


Ruby solution:

(1..10).to_a.repeated_permutation(3).select { |a, b, c| a*a + b*b == c*c }
# => [[3, 4, 5], [4, 3, 5], [6, 8, 10], [8, 6, 10]] 


Python solution, using itertools.product, which is equivalent to nested for-loops in a generator expression:

[(a,b,c) for c,b,a in product(range(1,11), repeat=3) if a*a + b*b == c*c]


A Ruby alternative without forcing identical ranges:

>> (1..10).to_a.product((1..10).to_a, (1..10).to_a).select { |a, b, c| a*a + b*b == c*c }
#=> [[3, 4, 5], [4, 3, 5], [6, 8, 10], [8, 6, 10]]

You can argue that this does not return the expected result, that's because you use c->b->a to iterate but return (a, b, c). So I am afraid in Ruby, having no list-comprehensions, we need to do something like this (map_select=map+compact):

>> (1..10).to_a.product((1..10).to_a, (1..10).to_a).map { |c, b, a| [a, b, c] if a*a + b*b == c*c }.compact
 #=> [[4, 3, 5], [3, 4, 5], [8, 6, 10], [6, 8, 10]]

Not vanilla Ruby, but using the cool library lazylist you can write:

>> list { [a, b, c] }.where(:c => (1..10), :b => (1..10), :a => (1..10)) { a*a + b*b == c*c }.to_a
#=> [[4, 3, 5], [3, 4, 5], [8, 6, 10], [6, 8, 10]]


(for [a (range 1 11)
  b (range 1 11)
  c (range 1 11) :when (=
                        (+ (* a a) (* b b))
                        (* c c))]
  [a b c])

A clojure example of the same.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜