Merging hashes and having trouble with variable scope!

Discussion in 'Ruby' started by Andy Pipes, Sep 28, 2008.

  1. Andy Pipes

    Andy Pipes Guest

    Hi.

    Caveat: I'm just learning Ruby coming from some basic PHP programming.

    In the following I am aiming to peer into two tab-separated files with
    some vegetable facts on them. In the first 'column' of each file there
    are vegetable names, followed by the data. However, whilst some of the
    vegetables have the same name, others do not. My ultimate aim is to take
    the contents of each of these files, and merge them into a master file,
    and for those vegetables that have data in both files to merge the data.

    So a line from file 1 might read:

    Watermelon 60-80 4-10

    and one file two:

    Watermelon 1/2oz. 34 12-26 24-48

    and in the masterfile I would want:

    Watermelon 60-80 4-10 1/2oz. 34 12-26 24-48.

    I have been trying unsuccessfully for the past two days to do this so
    any help is greatly appreciated!!! :)

    Here's some sample code:


    File.foreach("vegetables.txt") do |line|
    name, temp, germ_days = line.split /\t/
    #split min and max germination temps
    if temp =~ /-/
    temp_min, temp_max = temp.split /-/
    else temp_min = temp and temp_max = temp
    end
    # split the min and max germ days
    if germ_days =~ /-/
    germ_days_min, germ_days_max = germ_days.split /-/
    else germ_days_min = germ_days and germ_days_max = germ_days
    end

    # now iterate over the other table
    File.foreach("vegetables2.txt") do |l|
    name2, crop_yield, space_between_rows, space_between_plants,
    days_to_harvest = l.split /\t/
    #split min and max space between rows
    if space_between_rows =~ /-/
    space_between_rows_min, space_between_rows_max =
    space_between_rows.split /-/
    else
    space_between_rows_min = space_between_rows and
    space_between_rows_max = space_between_rows
    end
    # split the min and max space between plants
    if space_between_plants =~ /-/
    space_between_plants_min, space_between_plants_max =
    space_between_plants.split /-/
    else
    space_between_plants_min = space_between_plants and
    space_between_plants_max = space_between_plants
    end
    # split the min and max days to harvest
    if days_to_harvest =~ /-/
    days_to_harvest_min, days_to_harvest_max = days_to_harvest.split
    /-/
    else
    days_to_harvest_min = days_to_harvest and days_to_harvest_max =
    days_to_harvest
    end
    if name2 == name
    veggies = {
    :name => name2,
    :crop_yield => crop_yield,
    :temp_min => temp_min,
    :temp_max => temp_max,
    :germ_days_min => germ_days_min,
    :germ_days_max => germ_days_max,
    :space_between_plants_min => space_between_plants_min,
    :space_between_plants_max => space_between_plants_max,
    :space_between_rows_min => space_between_rows_min,
    :space_between_rows_max => space_between_rows_min,
    :days_to_harvest_min => days_to_harvest_min,
    :days_to_harvest_max => days_to_harvest_max
    }
    end

    puts veggies

    end
    end

    If I run this, I get local variable not found errors; I've tried a lot
    of variations, with no luck. I'm new to OO, and think that maybe I'm
    just 'not getting it' in this case.

    Can anyone help? Thanks in advance.

    Andy
    --
    Posted via http://www.ruby-forum.com/.
    Andy Pipes, Sep 28, 2008
    #1
    1. Advertising

  2. Andy Pipes

    Andy Pipes Guest

    Sorry: worth mentioning - I'm just trying to see what the output of the
    'veggies' hash is here, not writing it to a separate file yet..
    --
    Posted via http://www.ruby-forum.com/.
    Andy Pipes, Sep 28, 2008
    #2
    1. Advertising

  3. Hi --

    On Sun, 28 Sep 2008, Andy Pipes wrote:

    > Hi.
    >
    > Caveat: I'm just learning Ruby coming from some basic PHP programming.
    >
    > In the following I am aiming to peer into two tab-separated files with
    > some vegetable facts on them. In the first 'column' of each file there
    > are vegetable names, followed by the data. However, whilst some of the
    > vegetables have the same name, others do not. My ultimate aim is to take
    > the contents of each of these files, and merge them into a master file,
    > and for those vegetables that have data in both files to merge the data.
    >
    > So a line from file 1 might read:
    >
    > Watermelon 60-80 4-10
    >
    > and one file two:
    >
    > Watermelon 1/2oz. 34 12-26 24-48
    >
    > and in the masterfile I would want:
    >
    > Watermelon 60-80 4-10 1/2oz. 34 12-26 24-48.
    >
    > I have been trying unsuccessfully for the past two days to do this so
    > any help is greatly appreciated!!! :)
    >
    > Here's some sample code:


    Back at ya :) Try this. I've changed key names just to fit things on
    single lines and make my code look even slicker than it is :) You can
    change all that back, of course. The main thing is to absolutely not
    write that same splitting routine five times! I've syphoned it off
    into a method (and you could possibly even trim the arguments down if
    you automated the "min"/"max" parts).

    So, see if this helps as a starting point. It doesn't distinguish
    among different vegetables, but that could be added.

    @v = {}

    def split_or_double(string, key1, key2)
    @v[key1], @v[key2] = string.split(/-/)
    @v[key2] || @v[key1]
    end

    File.foreach("vegetables.txt") do |line|
    name, temp, germ_days = line.split
    split_or_double(temp, :temp_max, :temp_min)
    split_or_double(germ_days, :germ_days_max, :germ_days_min)
    end

    File.foreach("vegetables2.txt") do |line|
    name2, crop_yield, row_space, plant_space, harvest_days = line.split
    split_or_double(row_space, :min_row_space, :max_row_space)
    split_or_double(plant_space, :min_plant_space, :max_plant_space)
    split_or_double(harvest_days, :min_harvest, :max_harvest)
    end

    p @v


    David

    --
    Rails training from David A. Black and Ruby Power and Light:
    Intro to Ruby on Rails January 12-15 Fort Lauderdale, FL
    Advancing with Rails January 19-22 Fort Lauderdale, FL *
    * Co-taught with Patrick Ewing!
    See http://www.rubypal.com for details and updates!
    David A. Black, Sep 28, 2008
    #3
  4. Andy Pipes

    Todd Benson Guest

    On Sun, Sep 28, 2008 at 6:42 AM, Andy Pipes <> wrote:
    > Hi.
    >
    > Caveat: I'm just learning Ruby coming from some basic PHP programming.
    >
    > In the following I am aiming to peer into two tab-separated files with
    > some vegetable facts on them. In the first 'column' of each file there
    > are vegetable names, followed by the data. However, whilst some of the
    > vegetables have the same name, others do not. My ultimate aim is to take
    > the contents of each of these files, and merge them into a master file,
    > and for those vegetables that have data in both files to merge the data.
    >
    > So a line from file 1 might read:
    >
    > Watermelon 60-80 4-10
    >
    > and one file two:
    >
    > Watermelon 1/2oz. 34 12-26 24-48
    >
    > and in the masterfile I would want:
    >
    > Watermelon 60-80 4-10 1/2oz. 34 12-26 24-48.
    >
    > I have been trying unsuccessfully for the past two days to do this so
    > any help is greatly appreciated!!! :)
    >
    > Here's some sample code:
    >
    >
    > File.foreach("vegetables.txt") do |line|
    > name, temp, germ_days = line.split /\t/
    > #split min and max germination temps
    > if temp =~ /-/
    > temp_min, temp_max = temp.split /-/
    > else temp_min = temp and temp_max = temp
    > end
    > # split the min and max germ days
    > if germ_days =~ /-/
    > germ_days_min, germ_days_max = germ_days.split /-/
    > else germ_days_min = germ_days and germ_days_max = germ_days
    > end
    >
    > # now iterate over the other table
    > File.foreach("vegetables2.txt") do |l|
    > name2, crop_yield, space_between_rows, space_between_plants,
    > days_to_harvest = l.split /\t/
    > #split min and max space between rows
    > if space_between_rows =~ /-/
    > space_between_rows_min, space_between_rows_max =
    > space_between_rows.split /-/
    > else
    > space_between_rows_min = space_between_rows and
    > space_between_rows_max = space_between_rows
    > end
    > # split the min and max space between plants
    > if space_between_plants =~ /-/
    > space_between_plants_min, space_between_plants_max =
    > space_between_plants.split /-/
    > else
    > space_between_plants_min = space_between_plants and
    > space_between_plants_max = space_between_plants
    > end
    > # split the min and max days to harvest
    > if days_to_harvest =~ /-/
    > days_to_harvest_min, days_to_harvest_max = days_to_harvest.split
    > /-/
    > else
    > days_to_harvest_min = days_to_harvest and days_to_harvest_max =
    > days_to_harvest
    > end
    > if name2 == name
    > veggies = {
    > :name => name2,
    > :crop_yield => crop_yield,
    > :temp_min => temp_min,
    > :temp_max => temp_max,
    > :germ_days_min => germ_days_min,
    > :germ_days_max => germ_days_max,
    > :space_between_plants_min => space_between_plants_min,
    > :space_between_plants_max => space_between_plants_max,
    > :space_between_rows_min => space_between_rows_min,
    > :space_between_rows_max => space_between_rows_min,
    > :days_to_harvest_min => days_to_harvest_min,
    > :days_to_harvest_max => days_to_harvest_max
    > }
    > end
    >
    > puts veggies
    >
    > end
    > end
    >
    > If I run this, I get local variable not found errors; I've tried a lot
    > of variations, with no luck. I'm new to OO, and think that maybe I'm
    > just 'not getting it' in this case.
    >
    > Can anyone help? Thanks in advance.
    >
    > Andy


    For scope, you must establish for the interpreter that these variables
    exist outside of the File.foreach blocks.

    my_var = ""
    File.foreach {|line| #do_something_with_my_var}


    Personally, I might try using ranges (needs cleaning up)...

    #add method to range for building from
    # a string like "1-10"
    class Range
    def self.[](str)
    begin
    a = str.split(/-/)
    a[1] ||= [0]
    new(*(a.map {|i| Integer(i)})) rescue str
    end
    end
    end

    #just a method to split and change to ranges
    def collate_veggie str
    str.chomp.split(/\t/).map! {|elem| Range[elem]}
    end

    #first set of data
    veggies1 = {}
    keys1 = :temp, :germ_days
    File.foreach('veggies1.txt' ) do |line|
    values = collate_veggie line
    veggies1[values.shift] = keys1.zip values
    end

    #second set of data
    veggies2 = {}
    keys2 = :crop_yield, :row_space, :plant_space, :harvest_days
    File.foreach('veggies2.txt') do |line|
    values = collate_veggie line
    veggies2[values.shift] = keys2.zip values
    end

    #merge the two
    veggies = {}
    veggies1.each_key {|k| veggies[k] = Hash[*(veggies1[k] | veggies2[k]).flatten]}

    #use Range methods for min and max
    p h
    p h["Watermelon"][:germ_days].min
    p h["JuicyVeggie"][:plant_space].max


    just a thought,
    Todd
    Todd Benson, Sep 28, 2008
    #4
  5. Andy Pipes

    Todd Benson Guest

    On Sun, Sep 28, 2008 at 11:00 AM, Todd Benson <> wrote:

    > #use Range methods for min and max
    > p h
    > p h["Watermelon"][:germ_days].min
    > p h["JuicyVeggie"][:plant_space].max


    The h's should be veggies', so...

    p veggies
    p veggies["Watermelon"][:germ_days].min
    p veggies["JuicyVeggie"][:plant_space].max


    Oops,
    Todd
    Todd Benson, Sep 28, 2008
    #5
  6. Andy Pipes

    Todd Benson Guest

    On Sun, Sep 28, 2008 at 11:00 AM, Todd Benson <> wrote:

    > class Range
    > def self.[](str)
    > begin
    > a = str.split(/-/)
    > a[1] ||= [0]
    > new(*(a.map {|i| Integer(i)})) rescue str
    > end
    > end
    > end


    Another typo of mine. The a[1] ||= [0] should be a[1] ||= a[0].

    My apologies for these minor things, but I hand type in my answers,
    because, in using Gmail, my cut and pastes sometimes get "folded"
    (unseen unless "- Show quoted text -" is clicked upon).

    Todd
    Todd Benson, Sep 29, 2008
    #6
  7. Andy Pipes

    Andy Pipes Guest

    I'd just like to say thank you to both of you. Will have a go amending
    the (admittedly spaghetti) code later and see how it goes.

    best, andy
    --
    Posted via http://www.ruby-forum.com/.
    Andy Pipes, Sep 30, 2008
    #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. Pyenos
    Replies:
    9
    Views:
    279
    WaterWalk
    Dec 29, 2006
  2. Giles Bowkett
    Replies:
    13
    Views:
    232
    Jacob Fugal
    Mar 15, 2007
  3. shenry
    Replies:
    14
    Views:
    225
    Rick DeNatale
    Nov 3, 2009
  4. Tim O'Donovan

    Hash of hashes, of hashes, of arrays of hashes

    Tim O'Donovan, Oct 27, 2005, in forum: Perl Misc
    Replies:
    5
    Views:
    201
  5. Andrew Falanga
    Replies:
    2
    Views:
    193
    Andrew Falanga
    Nov 22, 2008
Loading...

Share This Page