Merging hashes and having trouble with variable scope!

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!!! :slight_smile:

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/.

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/.

Hi --

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!!! :slight_smile:

Here's some sample code:

Back at ya :slight_smile: Try this. I've changed key names just to fit things on
single lines and make my code look even slicker than it is :slight_smile: 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

···

On Sun, 28 Sep 2008, Andy Pipes wrote:

--
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!

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

···

On Sun, Sep 28, 2008 at 6:42 AM, Andy Pipes <mypipeline@btinternet.com> 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!!! :slight_smile:

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

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

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

Oops,
Todd

···

On Sun, Sep 28, 2008 at 11:00 AM, Todd Benson <caduceass@gmail.com> wrote:

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

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

···

On Sun, Sep 28, 2008 at 11:00 AM, Todd Benson <caduceass@gmail.com> wrote:

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

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/.