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
on 26.11.2006 00:48
on 26.11.2006 00:54
Brad Tilley wrote: > 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+this+group
on 26.11.2006 01:08
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.
on 26.11.2006 01:22
Brad Tilley wrote:
> 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
on 26.11.2006 01:30
Quoting Mike Austin <noone@nowhere.com>: > [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.
on 26.11.2006 23:46
On 2006-11-25 18:47:26 -0500, Brad Tilley <rtilley@vt.edu> said:
> 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
on 26.11.2006 23:54
Hi -- On Mon, 27 Nov 2006, James Cunningham wrote: >> Ruby? > 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
on 27.11.2006 01:06
On 2006-11-26 17:52:37 -0500, dblack@wobblini.net said: >>> same = [x for x in new_data if x in old_data] >> class Array >> added = new_data.comprehend { |x| x if not old_data.include? x } > 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
on 27.11.2006 01:06
On 2006-11-26 19:01:53 -0500, James Cunningham <jameshcunningham@gmail.com> said: >>>> added = [x for x in new_data if x not in old_data] >>> recall where I found it. It's a cute little hack. >>> Then: >> > Best, > James Er, "your" meaning "Brad Tilley's". Best, James
on 27.11.2006 09:10
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/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
on 27.11.2006 09:36
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
on 27.11.2006 10:51
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?
on 27.11.2006 11:01
On 11/26/06, Mike Austin <noone@nowhere.com> wrote: > > Brad Tilley wrote: > <snip> > Because Ruby's select() returns a value, not just a boolean like in > Smalltalk, > > OT of course ;) ... this does not seem true for all Smalltalks, I am using Squeak and select: returns the filtered array, I am quite surprised that it worked differently before. <snip> Robert -- The reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man. - George Bernard Shaw
on 27.11.2006 14:01
On 2006-11-27 03:30:58 -0500, Robert Klemme <shortcutter@googlemail.com> said: >> > > 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 That's fair enough, but I think list comprehension is clearer than method chaining and one-liner array accumulation. I'm afraid a << x**2 if x % 2 == 1; a is perhaps just a little less elegant than x**2 if x % 2 == 1 I think the nicest thing about Ruby, though, is that it's even possible. Best, James
on 27.11.2006 15:23
piggybox wrote: > 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. :)
on 28.11.2006 05:45
James Cunningham wrote:
> 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
on 28.11.2006 06:15
On 2006-11-27 23:39:57 -0500, "Phrogz" <gavin@refinery.com> said: > class Array > def comprehend( &block ) > block ? map( &block ).compact : self > end > end The same. You're just cleverer than I am. ;) Best, James
on 28.11.2006 11:36
On 28.11.2006 05:39, Phrogz wrote: > 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