grouping/sorting [newbie question]

Discussion in 'Ruby' started by bdarcus@gmail.com, Jun 26, 2005.

  1. Guest

    I'm trying to do something fairly simple that I understand how to do in
    XSLT, but not in Ruby.

    I have a list of film recommendations, with comments, in a yaml file
    that looks like this:

    -
    title: Lost in translation
    setting: Tokyo
    comments: Some comments..
    -
    title: Chungking Express
    setting: Hong Kong
    comments: >
    Some comments.

    Since a film may have more than one entry, I want to create a list that
    groups the comments by film. So I'd like output like:

    Some Film
    =======
    Comment 1.

    Comment 2.

    However, while I figured out how to sort the list correctly, I don't
    really understand how to do the grouping. Could someone please explain?

    Current code:

    require 'yaml'

    films = YAML::load(File.open("film.yaml"))

    sorted = films.sort_by{|film| film["title"]}

    sorted.each do |item|
    # I want to put the title for a group here,
    # then list the comments.
    if item["comments"] : puts item["comments"]
    else ''
    end
    end

    Bruce
     
    , Jun 26, 2005
    #1
    1. Advertising

  2. wrote:
    >
    > However, while I figured out how to sort the list correctly, I don't
    > really understand how to do the grouping. Could someone please explain?


    Inject is your friend:

    require 'yaml'

    films = YAML::load(File.open("film.yaml"))

    grouped_comments = films.inject({}) do |grouped, film|
    (grouped[film['title']] ||= []) << film['comments']
    grouped
    end

    grouped_comments.keys.sort.each do |title|
    puts "Comments for #{title}:"
    grouped_comments[title].each do |comment|
    puts "\t#{comment}"
    end
    end

    Ryan
     
    Ryan Leavengood, Jun 26, 2005
    #2
    1. Advertising

  3. Guest

    Thanks Ryan. Certainly less verbose than xslt!

    So when you;'re using inject there, you're just creating a hash whose
    key is the title?

    What is the "||=[]" bit doing?

    Bruce
     
    , Jun 26, 2005
    #3
  4. wrote:
    > Thanks Ryan. Certainly less verbose than xslt!


    Generally so. Here is an article by Martin Fowler about his switch from
    XSLT to Ruby for processing XML:

    http://www.martinfowler.com/bliki/MovingAwayFromXslt.html

    > So when you;'re using inject there, you're just creating a hash whose
    > key is the title?


    Correct. You give inject the initial value, which it injects into the
    block along with each value in the array. So we start with an empty hash
    and use the film titles as keys. The return value from the block is used
    to re-inject into the block (that is why I have the grouped hash at the
    bottom of the block.)

    > What is the "||=[]" bit doing?


    That is a bit of a Ruby idiom (that comes from Perl I think.) It is
    equivalent to var = var || []. If var is initially nil, it becomes a new
    array, and whenever the above code is called again, var is just
    re-assigned to itself. It just makes the code shorter. The verbose
    version from the code I sent is this:

    grouped_comments = films.inject({}) do |grouped, film|
    if grouped[film['title']].nil?
    grouped[film['title']] = []
    end
    grouped[film['title']] << film['comments']
    grouped
    end

    As you can see there is a lot of repetition, so it is a good idea to
    become familiar with this idiom.

    Ryan
     
    Ryan Leavengood, Jun 26, 2005
    #4
  5. Guest

    Ryan Leavengood wrote:
    > wrote:
    > > Thanks Ryan. Certainly less verbose than xslt!

    >
    > Generally so. Here is an article by Martin Fowler about his switch from
    > XSLT to Ruby for processing XML:
    >
    > http://www.martinfowler.com/bliki/MovingAwayFromXslt.html


    I saw that, though it'd be nice to have a fully functional example to
    try out. I couldn't manage how to get it working.

    Also, while Fowler's comments may apply well to XSLT 1.0, 2.0 adds a
    lot of power to the language. Still, it only goes so far of course,
    which is why I'm interested in Ruby and Python.

    > > What is the "||=[]" bit doing?

    >
    > That is a bit of a Ruby idiom (that comes from Perl I think.) It is
    > equivalent to var = var || []. If var is initially nil, it becomes a new
    > array, and whenever the above code is called again, var is just
    > re-assigned to itself.


    E.g. it only creates a new "group" if one doesn't already exist? Was
    wondering how to do that, so thanks for this!

    Bruce
     
    , Jun 26, 2005
    #5
  6. wrote:
    >
    > E.g. it only creates a new "group" if one doesn't already exist? Was
    > wondering how to do that, so thanks for this!


    That is one way. Hashes can also take a block in their constructors
    which can be used for default values:

    h = Hash.new {|h,k| h[k] = 'default'}
    h['foo'] = 'bar'
    p h['foo'] # => "bar"
    p h['baz'] # => "default"

    For the code I wrote before, it would be like this:

    grouped_comments = films.inject(Hash.new {|h,k| h[k] = []}) do |grouped,
    film|
    grouped[film['title']] << film['comments']
    grouped
    end

    But in this case I prefer the ||= syntax.

    Ryan
     
    Ryan Leavengood, Jun 26, 2005
    #6
  7. Florian Groß, Jun 27, 2005
    #7
    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. Myk Quayce

    Newbie: Grouping Commonly-used Methods

    Myk Quayce, Jun 16, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    323
    Paul Bobrowski
    Jun 16, 2004
  2. Christian Ludwig

    XSLT: sorting and grouping

    Christian Ludwig, Nov 24, 2003, in forum: XML
    Replies:
    2
    Views:
    623
    Christian Ludwig
    Nov 26, 2003
  3. Jack Wayne
    Replies:
    0
    Views:
    470
    Jack Wayne
    Jan 24, 2005
  4. Howard Roberts

    Grouping/Sorting an Array of objects

    Howard Roberts, Jul 21, 2008, in forum: Ruby
    Replies:
    5
    Views:
    159
    Erik Veenstra
    Jul 22, 2008
Loading...

Share This Page