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
> 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.
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
> 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.
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
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 | dbl...@wobblini.net
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
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
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
> 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
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?
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
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
> class Array
> def comprehend( &block )
> block ? map( &block ).compact : self
> end
> end
The same.
You're just cleverer than I am. ;)
Best,
James
This could go into Enumerable instead. There is no special Array
functionality involved.
Kind regards
robert