ruby and list comprehension

B

Brad Tilley

In Python, I can do this to arrays:

added = [x for x in new_data if x not in old_data]
removed = [x for x in old_data if x not in new_data]
same = [x for x in new_data if x in old_data]

I believe this is known as list comprehension in Python. How is this done in
Ruby?

Thanks,
Brad
 
T

Timothy Hunter

Brad said:
In Python, I can do this to arrays:

added = [x for x in new_data if x not in old_data]
removed = [x for x in old_data if x not in new_data]
same = [x for x in new_data if x in old_data]

I believe this is known as list comprehension in Python. How is this done in
Ruby?

Thanks,
Brad
This question comes up from time to time. You can search the archives of
comp.lang.ruby on Google Groups for "list comprehension" to find the
previous threads on this topic.

http://groups.google.com/group/comp...prehension&qt_g=1&searchnow=Search+this+group
 
L

Louis J Scoras

In Python, I can do this to arrays:

added = [x for x in new_data if x not in old_data]
removed = [x for x in old_data if x not in new_data]
same = [x for x in new_data if x in old_data]

Short answer:

added = new_data.reject {|i| old_data.include? i }
removed = old_data.reject {|i| new_data.include? i }
same = new_data.select {|i| old_data.include? i }

Provided ordering isn't important here, you can do the same thing with
set operations.

require 'set'

old_data = old_data.to_set
new_data = new_data.to_set

added = new_data - old_data
removed = old_data - new_data
same = new_data.intersection(old_data)

Note those returns sets, not arrays.
 
M

Mike Austin

Brad said:
In Python, I can do this to arrays:

added = [x for x in new_data if x not in old_data]
removed = [x for x in old_data if x not in new_data]
same = [x for x in new_data if x in old_data]

I believe this is known as list comprehension in Python. How is this done in
Ruby?

Thanks,
Brad

Because Ruby's select() returns a value, not just a boolean like in Smalltalk,
you can do the following:

[1,2,3].select { |x| ![2,3,4].include? x }
[2,3,4].select { |x| ![1,2,3].include? x }
[1,2,3].select { |x| [2,3,4].include? x }

You can also use Array operators:

[1,2,3] - [2,3,4]
[2,3,4] - [1,2,3]
[1,2,3] & [2,3,4]


Mike
 
B

Brad Tilley

Quoting Mike Austin said:
Because Ruby's select() returns a value, not just a boolean like in
Smalltalk,
you can do the following:

[1,2,3].select { |x| ![2,3,4].include? x }
[2,3,4].select { |x| ![1,2,3].include? x }
[1,2,3].select { |x| [2,3,4].include? x }

You can also use Array operators:

[1,2,3] - [2,3,4]
[2,3,4] - [1,2,3]
[1,2,3] & [2,3,4]

Thanks for all the examples guys! That's great stuff.
 
D

dblack

Hi --

In Python, I can do this to arrays:

added = [x for x in new_data if x not in old_data]
removed = [x for x in old_data if x not in new_data]
same = [x for x in new_data if x in old_data]

I believe this is known as list comprehension in Python. How is this done
in
Ruby?

Thanks,
Brad

I found this while web searching for the same thing recently; I can't recall
where I found it. It's a cute little hack.

class Array
def comprehend
return self unless block_given?
result = []
self.each { |i| result.push yield(i) }
result.compact
end
end

Then:

added = new_data.comprehend { |x| x if not old_data.include? x }
removed = old_data.comprehend { |x| x if not new_data.include? x }
same = new_data.comprehend { |x| x if old_data.include? x }

I'm not getting how that's better than:

added = new_data.select {|x| not old_data.include?(x) }

(or the reject equivalent) and so on.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

Martin DeMello

added = new_data.comprehend { |x| x if not old_data.include? x }
removed = old_data.comprehend { |x| x if not new_data.include? x }
same = new_data.comprehend { |x| x if old_data.include? x }

I wrote http://zem.novylen.net/ruby/fproduct.rb a while ago to emulate
list comprehensions in ruby - for example:

for x,y,z in product 1..40,
1..40, proc {|x,y| x <= y},
1..40, proc {|x,y,z| x**2 + y**2 == z**2}
p [x,y,z]
end

The benefit is that the filters do get applied in order (sorted on
arity), so that it doesn't generate all the combinations first and
then filter.

martin
 
R

Robert Klemme

I should have clarified. In your example there's no difference, but the
above gives a general replacement for list comprehensions.

irb(main):018:0> (1..25).to_a.comprehend { |x| x**2 if not x % 2 == 0 }
=> [1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625]

Frankly, I am not sure I find this better than using the built in methods:

irb(main):001:0> (1..25).inject([]) {|a,x| a << x**2 unless x % 2 == 0; a}
=> [1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625]

irb(main):002:0> (1..25).inject([]) {|a,x| a << x**2 if x % 2 == 1; a}
=> [1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625]

irb(main):003:0> (1..25).select {|x| x % 2 == 1}.map! {|x| x**2}
=> [1, 9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625]

Kind regards

robert
 
P

piggybox

I've always thought list comprehension is just a bunch of
map/filter/... transformation until I saw the following version of
permutation:

in Haskell:
permutation [] = [[]]
permutation xs = [x:ys | x <- xs, ys <- permutation (delete x xs)]

in Erlang:
permutation([]) -> [[]];
permutation(L) -> [[H|T] || H <- L, T <- permutation(L--[H])].

really neat, isn't it?
 
D

Devin Mullins

piggybox said:
in Haskell:
permutation [] = [[]]
permutation xs = [x:ys | x <- xs, ys <- permutation (delete x xs)]

in Erlang:
permutation([]) -> [[]];
permutation(L) -> [[H|T] || H <- L, T <- permutation(L--[H])].

really neat, isn't it?
Yes. :)
 
P

Phrogz

James said:
I found this while web searching for the same thing recently; I can't
recall where I found it. It's a cute little hack.

class Array
def comprehend
return self unless block_given?
result = []
self.each { |i| result.push yield(i) }
result.compact
end
end

Maybe I don't comprehend comprehending, but why the result/each instead
of map?

class Array
def comprehend
if block_given?
map{ |i| yield( i ) }.compact
else
self
end
end
end

or perhaps better

class Array
def comprehend( &block )
block ? map( &block ).compact : self
end
end
 
R

Robert Klemme

class Array
def comprehend( &block )
block ? map( &block ).compact : self
end
end


This could go into Enumerable instead. There is no special Array
functionality involved.

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top