[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

ruby and list comprehension

Brad Tilley

11/25/2006 11:47:00 PM

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

16 Answers

Tim Hunter

11/25/2006 11:53:00 PM

0

Brad Tilley wrote:
> 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.lang.ruby/search?group=comp.lang.ruby&q=list+comprehension&qt_g=1&searchnow=Search+...

Louis J Scoras

11/26/2006 12:07:00 AM

0

On 11/25/06, Brad Tilley <rtilley@vt.edu> wrote:

> 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.


--
Lou.

Clint

11/26/2006 12:20:00 AM

0

Brad Tilley wrote:
> 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

Brad Tilley

11/26/2006 12:30:00 AM

0

Quoting Mike Austin <noone@nowhere.com>:

> 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.

jameshcunningham@gmail.com

11/26/2006 10:42:00 PM

0

On 2006-11-25 18:47:26 -0500, Brad Tilley <rtilley@vt.edu> 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

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 }

Best,
James

dblack

11/26/2006 10:53:00 PM

0

jameshcunningham@gmail.com

11/27/2006 12:02:00 AM

0

On 2006-11-26 17:52:37 -0500, dblack@wobblini.net said:

> Hi --
>
> On Mon, 27 Nov 2006, James Cunningham wrote:
>
>> On 2006-11-25 18:47:26 -0500, Brad Tilley <rtilley@vt.edu> 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
>>
>> 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


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]

Best,
James

jameshcunningham@gmail.com

11/27/2006 12:04:00 AM

0

On 2006-11-26 19:01:53 -0500, James Cunningham
<jameshcunningham@gmail.com> said:

> On 2006-11-26 17:52:37 -0500, dblack@wobblini.net said:
>
>> Hi --
>>
>> On Mon, 27 Nov 2006, James Cunningham wrote:
>>
>>> On 2006-11-25 18:47:26 -0500, Brad Tilley <rtilley@vt.edu> 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
>>>
>>> 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
>
>
> 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]
>
> Best,
> James

Er, "your" meaning "Brad Tilley's".

Best,
James

Martin DeMello

11/27/2006 8:09:00 AM

0

On 11/27/06, James Cunningham <jameshcunningham@gmail.com> wrote:
>
> 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/f... 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

Robert Klemme

11/27/2006 8:31:00 AM

0

On 27.11.2006 01:01, James Cunningham wrote:
> On 2006-11-26 17:52:37 -0500, dblack@wobblini.net said:
>> 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.

> 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