# Hash keys

**URL:** <https://www.ruby-forum.com/t/hash-keys/135732>\
**Category:** Ruby\
**Created:** [April 24, 2008, 3:12pm UTC](https://www.ruby-forum.com/t/hash-keys/135732 "2008-04-24T15:12:24Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![twaters](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a6a055/32.png) [@twaters](https://www.ruby-forum.com/u/twaters)\
**Post date:** [April 24, 2008, 3:12pm UTC](https://www.ruby-forum.com/t/hash-keys/135732/1 "2008-04-24T15:12:24Z")

</div>

Morning,

I am working on some code to gather accounts and their balances from a  
text  
file and have a question about adding that data to a hash. While  
checking  
to see if the account number is a key in the existing hash using  
has\_key?(key), canÂ¹t I use the variable that has the account number in  
it or  
do I have to use the actual account number? When I run my code to check  
it I  
get undefined method `has\_key?’ for nil:NilClass. I ran a test using  
just  
the account number in irb and it works but I would think you could use a  
variable to iterate of my list of account numbers… Thanks in advance

class Info  
attr\_reader :acct, :money

def initialize(filename)  
@acct = File.new(filename, “r”)  
end  
f = Info.new(“Balances20080415.txt”)  
act = f.acct  
act.each do |list|  
#covert me to a string  
futbal = list.to\_s  
#Pull accounts  
office = futbal[21…23]  
if office == “RPT”  
next  
else  
acctnum = futbal[24…28]  
lv = futbal[217…230]  
lvind = futbal[215…215]  
lvadd = lvind+lv  
lvadd.to\_f/100  
end  
#if Negitave vlaues  
if lvind == “-”  
lvnegfloat = lv.to\_f/100  
#print acctnum," “,lvind, lvnegfloat, “\n”  
#puts lvadd  
sktylist = Hash.new(”")  
#if(sktylist.has\_key?(23))  
# sktylist = { acctnum =\> lvind,lvnegfloat }

```
          sktylist[acctnum] = lvind,lvnegfloat
          sktylist.each { |key, value| puts "#{key} equals #{value}" 

```

}  
#else Positive Values

```
        elsif sktylist.has_key?('acctnum')
                puts "found #{key}second key"
            #lvposflt = lv.to_f/100

            #print acctnum, " ", lvposflt, "\n"
          end
        end

```

end

---

<div class="post-metadata">

**Author:** ![twaters](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a6a055/32.png) [@twaters](https://www.ruby-forum.com/u/twaters)\
**Post date:** [April 24, 2008, 4:29pm UTC](https://www.ruby-forum.com/t/hash-keys/135732/2 "2008-04-24T16:29:23Z")

</div>

On Apr 24, 9:11 am, Tim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> futbal = list.to_s
> end
> sktylist.each { |key, value| puts "#{key} equals #{value}" }
> 
> ```
> 
> end  
> Your if clauses looked messed up. The no method error doesn’t have  
> anything to do with the key of has\_key. You actually have no hash to  
> speak of.

T.

---

<div class="post-metadata">

**Author:** ![twaters](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a6a055/32.png) [@twaters](https://www.ruby-forum.com/u/twaters)\
**Post date:** [April 24, 2008, 4:41pm UTC](https://www.ruby-forum.com/t/hash-keys/135732/3 "2008-04-24T16:41:19Z")

</div>

> > ```
> > futbal = list.to_s
> > end
> > sktylist.each { |key, value| puts "#{key} equals #{value}" }
> > 
> > ```
> > 
> > end
> 
> Your if clauses looked messed up. The no method error doesn’t have  
> anything to do with the key of has\_key. You actually have no hash to  
> speak of.
> 
> T.

The first if does return a hash with the keys and values so I know that  
works. The first one is for any negative values as it is only indicated  
by  
a 0 or a - in position 215 of the string. The second if is for the  
positive  
values, so I’m guessing that when the script is processing the lines and  
has  
a positive value its not skipping the negative if and going to the elsif  
to  
process and store the info in the hash.

Basically what I’m trying to do here is gather the account balances and  
account numbers and store them in a hash and if there are accounts with  
the  
same number to store their balances as an array in the hash value to add  
them later when I iterate over the hash.

If there is a better way to do this that I’m not thinking of please  
share  
with me so I can better my ruby knowledge.

Thanks!  
Tim

---

<div class="post-metadata">

**Author:** ![twaters](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a6a055/32.png) [@twaters](https://www.ruby-forum.com/u/twaters)\
**Post date:** [April 24, 2008, 5:39pm UTC](https://www.ruby-forum.com/t/hash-keys/135732/4 "2008-04-24T17:39:19Z")

</div>

Tim W. wrote:

> (…)  
> Basically what I’m trying to do here is gather the account balances and  
> account numbers and store them in a hash and if there are accounts with  
> the  
> same number to store their balances as an array in the hash value to add  
> them later when I iterate over the hash.
> 
> If there is a better way to do this that I’m not thinking of please  
> share  
> with me so I can better my ruby knowledge.
> 
> Thanks!  
> Tim

The following code does not store an array in a hash, it just stores a  
running total:

DATA.gets  
#DATA is the stuff below **END**  
#you can treat it like a file.  
#DATA.gets just gets the first line and ignores it.

totalled = Hash.new(0)  
#Thanks to the (0) parameter, totalled will return 0 if a key is not  
found.

DATA.each do |line|  
ar\_line = line.split(",")  
account, balance = ar\_line[0], ar\_line[1].to\_f  
totalled[account] = totalled[account] + balance  
#this line does the job. For the first line  
#read in the loop, the key “101” is not found in the hash  
#so it returns 0. Then the balance is added.  
#The key and the new (running) balance are stored.  
#A shorter way to write this is:  
#totalled[account] += balance  
end  
p totalled

**END**  
account,balance  
101,100.00  
102,500.00  
101,-57.00  
103,0.50  
102,1

##end code

prints: {“101”=\>43.0, “102”=\>501.0, “103”=\>0.5}

If you really need the hash with an array, replace the first line with:  
totalled = Hash.new([])  
(giving a ‘default value’ of an empty array); Also replace this line:  
totalled[account] = totalled[account] + balance  
with  
totalled[account]=totalled[account]\<\<balance  
HTH,

Siep

---

<div class="post-metadata">

**Author:** ![twaters](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/a6a055/32.png) [@twaters](https://www.ruby-forum.com/u/twaters)\
**Post date:** [April 24, 2008, 5:45pm UTC](https://www.ruby-forum.com/t/hash-keys/135732/5 "2008-04-24T17:45:55Z")

</div>

On Thu, Apr 24, 2008 at 9:40 AM, Tim W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> them later when I iterate over the hash.
> 
> If there is a better way to do this that I’m not thinking of please share  
> with me so I can better my ruby knowledge.
> 
> Thanks!  
> Tim

Here are some ideas. You create the Hash using a block, this will  
give you a default value for newly created hash pairs. You iterate  
over the file line by line, you skip the lines that have an office  
code of RPT. Otherwise, you pull out the account number and the  
balance. You add the balance in to the hash pair for that account  
number. If no values have been put in yet, you’ll add it to 0.  
Otherwise, you’ll add it to the previous value. There is no need to  
handle negative numbers in some special fashion, Ruby will know if  
it’s a negative number when it sees the ‘-’ at the beginning of the  
string.

I’m assuming you don’t want whatever is at position 216 to be part of  
your balance, so you concatenate the character at 215 to the rest of  
the balance in positions 217 to 230. You now have a string  
representation of your balance, you call to\_f on that and it will be a  
positive or negative number.

act = File.new(“Balances20080415.txt”, ‘r’)

# The default for a newly created value is 0

act.each do |list|

# list already is a string, no need to

# do this

# futbal = list.to\_s

#Pull accounts  
office = list[21…23]  
unless office == “RPT”  
acctnum = list[24…28]  
lvind = list[215,1]  
lvnum = list[217…230]  
lv = (lvind+lvnum).to\_f/100  
sktylist[acctnum] += lv  
end  
end

p sktylist
