newbie, get index or reorder array (insert) by regexp

Discussion in 'Ruby' started by Timothy Byrd, Feb 23, 2005.

  1. Timothy Byrd

    Timothy Byrd Guest

    Hi all,

    I'm just beginning to "get" Ruby. (Coming from a mostly C/C++
    background), and I have a question.

    I want to rearrange some elements in an array. For a simple example,
    given this:

    a = %w(Ruby is useful C++ is very very useful)
    b, c = a.partition {|w| w =~ /^v/}

    then either of these commands seem to do what I want:

    c.insert(c.index( c.find {|i| i =~ /^u/} ), b).flatten

    or

    c[c.index( c.find {|i| i =~ /^u/} ),0] = b

    Yes, it works, but the nested calls to #index and #find seem ugly to
    me. It seems there ought to be a cleaner way to get the index of the
    first item matching the pattern. Or is there a more Ruby-like way to
    do this?

    Btw, the reason for this is that I want to generate a list of my CDs
    off of my local CDDB database. But I want to sort artists like
    "Loreena McKennitt" as "McKennitt, Loreena", so I'm going to put some
    custom comments in the files, e.g. - "#SORT=McKennitt, Loreena" and
    then use them in the ruby script that generates the list. According to
    the CDDB standard, though, all comment lines for a record must precede
    any lines with keywords, so I want to insert them in the middle.

    Thanks,

    -- Timothy
     
    Timothy Byrd, Feb 23, 2005
    #1
    1. Advertising

  2. Timothy Byrd

    Csaba Henk Guest

    On 2005-02-23, Timothy Byrd <> wrote:
    > Hi all,
    >
    > I'm just beginning to "get" Ruby. (Coming from a mostly C/C++
    > background), and I have a question.
    >
    > I want to rearrange some elements in an array. For a simple example,
    > given this:
    >
    > a = %w(Ruby is useful C++ is very very useful)
    > b, c = a.partition {|w| w =~ /^v/}
    >
    > then either of these commands seem to do what I want:
    >
    > c.insert(c.index( c.find {|i| i =~ /^u/} ), b).flatten
    >
    > or
    >
    > c[c.index( c.find {|i| i =~ /^u/} ),0] = b


    As I see there is somewhat difference between the two solutions.

    In the first case, the expression returns the array you need, but c won't
    refer to that array.

    In the second case, c will refer to the desired array, but the
    expression doesn't return this array, you'll also have to
    append a c to get it...

    Nevermind.

    Better patterns for that index + find part:

    (0...c.size).find{|i| c =~ /^u/ }

    or if you are sure it will match somewhere:

    c.each_index {|i| break i if c =~ /^u/ }

    (if it didn't match, it would return an array with the numbers from zero
    to c.size, excluding the latter).


    > Yes, it works, but the nested calls to #index and #find seem ugly to
    > me. It seems there ought to be a cleaner way to get the index of the
    > first item matching the pattern. Or is there a more Ruby-like way to
    > do this?


    Imho it would be great to have a method Array#each_with_index (but with
    a better name than this :) ) which behaves as follows:

    c.each_with_index {|i,v| break i if v =~ /^u/ }

    (It's mainly an issue if you work with an anonymous array (eg., a slice
    of some other array, or a result of Array#map) -- then you can't get the
    value at the given index in the way as it's done above, simply by
    writing "c").

    Csaba
     
    Csaba Henk, Feb 23, 2005
    #2
    1. Advertising

  3. Timothy Byrd wrote:

    > Btw, the reason for this is that I want to generate a list of my CDs
    > off of my local CDDB database. But I want to sort artists like
    > "Loreena McKennitt" as "McKennitt, Loreena", so I'm going to put some
    > custom comments in the files, e.g. - "#SORT=McKennitt, Loreena" and
    > then use them in the ruby script that generates the list.


    irb(main):002:0> "Loreena Sue McKennitt".sub(/(.*) (.*?)$/,'\2, \1')
    => "McKennitt, Loreena Sue"
     
    William James, Feb 23, 2005
    #3
  4. Timothy Byrd

    Timothy Byrd Guest

    Csaba Henk wrote:
    > In the first case, the expression returns the array you need, but c
    > won't refer to that array.


    Huh? Oh. My fault - I was using #flatten! and failed to copy/paste the
    bang sign. That should assign to c, since #insert is also
    self-modifying (hard to use the word "destructive" here).

    Anyway, yeah, a #find_index method would have been handy. But now, I
    may not need it (see below). And it's a beauty of Ruby that if I do
    need it in the future, I should simply be able to extend either Array
    or Enumerable.

    William James wrote:
    > irb(main):002:0> "Loreena Sue McKennitt".sub(/(.*) (.*?)$/,'\2, \1')
    > => "McKennitt, Loreena Sue"


    True, but I still want to sort "Jethro Tull" under the 'J's. :)

    Also in certain cases, I want to change how an artist or album title
    appears in my list. As an example I want "Kim Robertson and Virginia
    Kron / Gratitude" to appear as "Kim Robertson - Gratitude" so I can put
    her albums in chronological order.

    I got it working (except for a final tweak to the list format) last
    night - and then realized I was stupid. I'd gone so far as to make a
    script to gather all my custom comments into a text file, so I could
    re-apply them to the database. At that point, I thought, why bother
    modifying all the CDDB files, when I can just fold in my custom changes
    when I make the list?

    Time to simplify.

    The last bit is a simple puzzle (did it in C years ago) - I just want
    to find a clever Ruby-ish way to do it.

    Given a list of albums:

    albums = [
    "Apocalyptica - Plays Metallica By Four Cellos",
    "Kim Robertson - Gratitude",
    "Synergy - Electronic Realizations For Rock Orchestra",
    "Synergy - Sequencer",
    "Synergy - Chords",
    "Synergy - Games",
    ]

    I want the list output to look like:

    1.\tApocalyptica - Plays Metallica By Four Cellos
    2.\tKim Robertson - Gratitude
    \tSynergy:
    3.\t- Electronic Realizations For Rock Orchestra
    4.\t- Sequencer
    5.\t- Chords
    6.\t- Games

    So if an artist has more than one album, I'll gather the albums under
    the artist. It's close to trivial, and there are a ton of ways to do
    this, so I'll have fun. First I'll write it in a C-like style, then
    I'll try Ruby-ifying it.

    -- Timothy
     
    Timothy Byrd, Feb 23, 2005
    #4
    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. Shapper

    Is it possible to reorder a dataset?

    Shapper, Jun 19, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    618
    Brock Allen
    Jun 19, 2005
  2. farseer
    Replies:
    1
    Views:
    2,395
    farseer
    Jun 28, 2005
  3. K B
    Replies:
    0
    Views:
    434
  4. Joao Silva
    Replies:
    16
    Views:
    381
    7stud --
    Aug 21, 2009
  5. Tomasz Chmielewski

    sorting index-15, index-9, index-110 "the human way"?

    Tomasz Chmielewski, Mar 4, 2008, in forum: Perl Misc
    Replies:
    4
    Views:
    323
    Tomasz Chmielewski
    Mar 4, 2008
Loading...

Share This Page