From: Todd Benson Date: 2008-09-29T00:59:48+09:00 Subject: Re: Merging hashes and having trouble with variable scope! 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