# Merging hashes and having trouble with variable scope!

**URL:** <https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695>\
**Category:** Ruby\
**Created:** [September 28, 2008, 1:42pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695 "2008-09-28T13:42:44Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 28, 2008, 1:42pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/1 "2008-09-28T13:42:44Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 28, 2008, 2:01pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/2 "2008-09-28T14:01:28Z")

</div>

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…

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 28, 2008, 3:01pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/3 "2008-09-28T15:01:29Z")

</div>

Hi –

On Sun, 28 Sep 2008, Andy P. wrote:

> 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

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 28, 2008, 6:01pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/4 "2008-09-28T18:01:33Z")

</div>

On Sun, Sep 28, 2008 at 6:42 AM, Andy P. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Watermelon 60-80 4-10 1/2oz. 34 12-26 24-48.  
> if temp =~ /-/  
> File.foreach(“vegetables2.txt”) do |l|  
> # split the min and max space between plants  
> /-/  
> :germ\_days\_min =\> germ\_days\_min,  
> puts veggies  
> 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.  
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

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 29, 2008, 2:03am UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/5 "2008-09-29T02:03:08Z")

</div>

On Sun, Sep 28, 2008 at 11:00 AM, Todd B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> class Range  
> def self.  
> 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

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 30, 2008, 4:44pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/6 "2008-09-30T16:44:38Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![prot](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@prot](https://www.ruby-forum.com/u/prot)\
**Post date:** [September 28, 2008, 6:03pm UTC](https://www.ruby-forum.com/t/merging-hashes-and-having-trouble-with-variable-scope/149695/7 "2008-09-28T18:03:54Z")

</div>

On Sun, Sep 28, 2008 at 11:00 AM, Todd B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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
