ruby and list comprehension

Discussion in 'Ruby' started by Brad Tilley, Nov 25, 2006.

  1. Brad Tilley

    Brad Tilley Guest

    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
     
    Brad Tilley, Nov 25, 2006
    #1
    1. Advertising

  2. 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...prehension&qt_g=1&searchnow=Search this group
     
    Timothy Hunter, Nov 25, 2006
    #2
    1. Advertising

  3. On 11/25/06, 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]


    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.
     
    Louis J Scoras, Nov 26, 2006
    #3
  4. Brad Tilley

    Mike Austin Guest

    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
     
    Mike Austin, Nov 26, 2006
    #4
  5. Brad Tilley

    Brad Tilley Guest

    Quoting Mike Austin <>:

    > 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.
     
    Brad Tilley, Nov 26, 2006
    #5
  6. Brad Tilley

    Guest

    Hi --

    On Mon, 27 Nov 2006, James Cunningham wrote:

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

    --
    David A. Black |
    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
     
    , Nov 26, 2006
    #6
  7. On 11/27/06, James Cunningham <> 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
     
    Martin DeMello, Nov 27, 2006
    #7
  8. On 27.11.2006 01:01, James Cunningham wrote:
    > On 2006-11-26 17:52:37 -0500, 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
     
    Robert Klemme, Nov 27, 2006
    #8
  9. Brad Tilley

    piggybox Guest

    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?
     
    piggybox, Nov 27, 2006
    #9
  10. 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. :)
     
    Devin Mullins, Nov 27, 2006
    #10
  11. Brad Tilley

    Phrogz Guest

    James Cunningham wrote:
    > 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
     
    Phrogz, Nov 28, 2006
    #11
  12. 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
     
    Robert Klemme, Nov 28, 2006
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Barth

    Mix lambda and list comprehension?

    Peter Barth, Jul 15, 2003, in forum: Python
    Replies:
    4
    Views:
    423
    Michele Simionato
    Jul 17, 2003
  2. William Park
    Replies:
    0
    Views:
    598
    William Park
    Aug 2, 2004
  3. Shane Geiger
    Replies:
    4
    Views:
    403
    bullockbefriending bard
    Mar 25, 2007
  4. Debajit Adhikary
    Replies:
    17
    Views:
    707
    Debajit Adhikary
    Oct 18, 2007
  5. Vedran Furac(
    Replies:
    4
    Views:
    348
    Marc 'BlackJack' Rintsch
    Dec 19, 2008
Loading...

Share This Page