[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Merging hashes and having trouble with variable scope!

Andy Pipes

9/28/2008 11:42:00 AM

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

6 Answers

Andy Pipes

9/28/2008 12:01:00 PM

0

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

David A. Black

9/28/2008 1:00:00 PM

0

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.r... for details and updates!

Todd Benson

9/28/2008 4:00:00 PM

0

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

9/28/2008 4:02:00 PM

0

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

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

9/29/2008

0

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

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

Andy Pipes

9/30/2008 2:44:00 PM

0

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