Jump to content

List comprehensions: Difference between revisions

→‎{{header|Ruby}}: Switch to using Enumerable#select.
m (→‎{{header|Scheme}}: Add link to SRFI-42)
(→‎{{header|Ruby}}: Switch to using Enumerable#select.)
Line 704:
 
=={{header|Ruby}}==
Enumerable#select comprises a list from one variable (like grep() in Perl).
A couple of ways, neither feel particularly elegant. Ruby's OO style really enforces writing left-to-right.
<div style="width:full;overflow:scroll"><lang ruby># using a storage array
a=[]; (1..n).each {|x| (1..n).each {|y| (1..n).each {|z| a << [x,y,z] if x**2 + y**2 == z**2}}}; a
 
* <tt>(1..100).select { |x| x % 3 == 0 }</tt> is the list of all x, from 1 to 100, such that x is a multiple of 3.
# no temp array, but a lot of housework to flatten and remove nils
* <tt>methods.select { |name| name.length <= 5 }</tt> is the list of all names, from methods of <tt>self</tt>, such that each name is not longer than 5 characters.
(1..n).collect {|x| (1..n).collect {|y| (1..n).collect {|z| [x,y,z] if x**2 + y**2 == z**2}}}.reduce(:+).reduce(:+).compact</lang></div>
 
Ruby's object-oriented style enforces writing 1..100 before x. Think not of x in 1..100. Think of 1..100 giving x.
 
There is no elegant way to comprise a list from multiple variables. Pythagorean triplets need three variables, with 1..n giving x, then x..n giving y, then y..n giving z. A less than elegant way is to nest three calls to Enumerable#map, to bundle these 3 variables into an array [x, y, z].
 
=== Ruby 1.9.2 ===
{{works with|Ruby|1.9.2 or later}}
 
<lang ruby>n = 20
 
# select Pythagorean triplets
r = ((1..n).flat_map { |x|
(x..n).flat_map { |y|
(y..n).map { |z| [x, y, z] }}} \
.select { |x, y, z| x * x + y * y == z * z })
 
p r # print the array _r_</lang>
 
Output: <tt>[[3, 4, 5], [5, 12, 13], [6, 8, 10], [8, 15, 17], [9, 12, 15], [12, 16, 20]]</tt>
 
Ruby 1.9.2 introduces a new method, Enumerable#flat_map.
 
* The inner <tt>(y..n).map { ... }</tt> returns an array of all triplets for all z given some x, y.
* The middle <tt>(x..n).flat_map { ... }</tt> concatenates the inner arrays for all y given some x.
* The outer <tt>(1..n).flat_map { ... }</tt> concatenates the middle arrays for all x.
* We never flatten the triplets; the inner <tt>map</tt> is not <tt>flat_map</tt>. So we produce an array of triplets like [[1, 1, 1], [1, 1, 2]], not a flat array like [1, 1, 1, 1, 1, 2].
* The final <tt>.select { ... }</tt> looks at each triplet in our array of triplets, and comprises the Pythagorean triplets.
 
=== Ruby 1.8.7 ===
{{works with|Ruby|1.8.7 or later}}
 
<lang ruby>n = 20
 
# select Pythagorean triplets
r = ((1..n).map { |x|
(x..n).map { |y|
(y..n).map { |z| [x, y, z] }}}.flatten(2) \
.select { |x, y, z| x * x + y * y == z * z })
 
p r # print the array _r_</lang>
 
Ruby before 1.9.2 is without Enumerable#flat_map, so we switch to using Enumerable#map. We get an array of arrays of arrays of triplets. We use <tt>.flatten(2)</tt> to convert this to an array of triplets.
 
* <tt>map</tt> and <tt>collect</tt> are the same method.
* <tt>.flatten(2)</tt> is a shorter alternative to <tt>.reduce(:+).reduce(:+)</tt>.
 
=== Ruby 1.8.6 ===
{{works with|Ruby|1.8.6}}
 
<lang ruby>n = 20
 
# select Pythagorean triplets
r = ((1..n).map { |x|
(x..n).map { |y|
(y..n).map { |z| [x, y, z] }}} \
.inject([]) { |a, b| a.concat b } \
.inject([]) { |a, b| a.concat b } \
.select { |x, y, z| x * x + y * y == z * z })
 
p r # print the array _r_</lang>
 
Anyone with Ruby 1.8.6 should probably upgrade to Ruby 1.8.7.
 
=={{header|Scala}}==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.