Hash adding values

I’m trying to insert account numbers into a hash and add the balances
together that are stored in the value. Is there a reason this is not
working?

sktylist = Hash.new("")
sktylist[@acctnum] += [value]
p sktylist

Tim W. wrote:

Is there a reason this is not
working?

sktylist = Hash.new("")
      sktylist[@acctnum] += [value]
     p sktylist

Yes, there is: String#+ does not expect an array as an argument.
sktylist[@acctnum] += value would work if value is a string.
(Alternatively you could change the hash to hold arrays instead
of strings and keep the += [value] part as-is, if that’s what
you want).

HTH,
Sebastian

Sebastian H. wrote:

Tim W. wrote:

Is there a reason this is not
working?

sktylist = Hash.new("")
      sktylist[@acctnum] += [value]
     p sktylist

Yes, there is: String#+ does not expect an array as an argument.
sktylist[@acctnum] += value would work if value is a string.
(Alternatively you could change the hash to hold arrays instead
of strings and keep the += [value] part as-is, if that’s what
you want).

HTH,
Sebastian

So would it be easier converting it to a string or have the hash hold
arrays? All I need is the value to be an array? Is there an easy way
to do this?

Thanks for the help.
Tim

Oh, you want to store the balances based on the acct. #, then you want
to
iterate the balances later and sum them?

On Wed, May 7, 2008 at 1:43 PM, Tim W. [email protected] wrote:

I’m trying to insert account numbers into a hash and add the balances
together that are stored in the value. Is there a reason this is not
working?

sktylist = Hash.new(“”)
sktylist[@acctnum] += [value]
p sktylist

According to docs for Hash.new, you’re initializing the Hash and telling
it
that the default value for any new elements is an empty string. Then,
you
might be accessing the hash with a key that doesn’t exist, so you’re
getting
that default value, the empty string. Then you’re trying to concatenate
an
array to it. I assume that you don’t want to do that based on your
problem
description. Maybe you want to do something like this (from an IRB
session):

$ irb

h = Hash.new(0.0)
=> {}
h[“a”] += 2.2
=> 2.2
h[“a”] += 3
=> 5.2
h
=> {“a”=>5.2}

Regards,
Craig

Craig D. wrote:

Oh, you want to store the balances based on the acct. #, then you want
to
iterate the balances later and sum them?

Yes, I need to take the accounts that have the same number and leave the
key that same number and sum the balances that are stored in the value
for that account. Then I can iterate over the hash and print the account
nums and balances in an email.

Thanks,
Tim

Something like this?

h = Hash.new( [] )
=> {}

h[“a”] << 2.2
=> [2.2]

h[“a”] << 3
=> [2.2, 3]

sum_of_a = 0.0
=> 0.0

h[“a”].inject { |sum_of_a, value| sum_of_a += value }
=> 5.2

sum_of_a
=> 5.2

I have no idea if that’s the best way to do that; I’m still earning my
Ruby
chops.

Regards,
Craig

I posted some code just before you replied. Did it help?

Craig D. wrote:

Something like this?

h = Hash.new( [] )
=> {}

h[“a”] << 2.2
=> [2.2]

h[“a”] << 3
=> [2.2, 3]

sum_of_a = 0.0
=> 0.0

h[“a”].inject { |sum_of_a, value| sum_of_a += value }
=> 5.2

sum_of_a
=> 5.2

I have no idea if that’s the best way to do that; I’m still earning my
Ruby
chops.

Regards,
Craig

I’m pretty new to ruby as well. I have the following and its saying
“can’t conver float into a string”. Keep in mind that the accounts and
balances are stored in variables.

class Info
attr_reader :acct, :money

def initialize(filename)
@acct = File.new(filename, “r”)
end

f = Info.new("SKTYFutBalances20080415.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]
    end
    #Pull Liquidating values
      @lv = futbal[217..230]
    #Pull LV Indicator
      is_negative = futbal[215..215] == '-'
      value = @lv.to_f/100
      value = -value if is_negative
      #puts @acctnum,value
     #test = @acctnum.to_sym
        sktylist = Hash.new("")
        sktylist[ @acctnum ] << value

     p sktylist
end

end

Craig D. wrote:

I posted some code just before you replied. Did it help?

I did not store anything when I run it with my code I posted I get:

{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}
{}

Looks like you forgot to change this line

sktylist = Hash.new("")

to

sktylist = Hash.new( [] )

which makes the default value for new elements an empty array instead of
a
string. Only then can you use the << operator to push values on to the
array.

Regards,
Craig

Craig D. wrote:

Looks like you forgot to change this line

sktylist = Hash.new("")

to

sktylist = Hash.new( [] )

which makes the default value for new elements an empty array instead of
a
string. Only then can you use the << operator to push values on to the
array.

Regards,
Craig

Still get the same thing, sorry I must be doing it wrong…

class Info
attr_reader :acct, :money

def initialize(filename)
@acct = File.new(filename, “r”)
end

f = Info.new("SKTYFutBalances20080415.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]
    end
    #Pull Liquidating values
      @lv = futbal[217..230]
    #Pull LV Indicator
      is_negative = futbal[215..215] == '-'
      value = @lv.to_f/100
      value = -value if is_negative
      #puts @acctnum,value
     #test = @acctnum.to_sym
        sktylist = Hash.new( [] )
        sktylist[ @acctnum ] << value

     p sktylist
end

end

Craig D. wrote:

Looks like you forgot to change this line

sktylist = Hash.new("")

to

sktylist = Hash.new( [] )

which makes the default value for new elements an empty array instead of
a
string. Only then can you use the << operator to push values on to the
array.

Regards,
Craig

You mean the block form: Hash.new{ [] }
Tim, you don’t have to do classes.

f = Info.new(“SKTYFutBalances20080415.txt”)
@sktylist1 = Hash.new{ [] } #with curly braces
@sktylist2 = Hash.new(0)
f.each do |list|

parsing stuff here

@sktylist1[ @acctnum ] = @sktylist1[ @acctnum ] << value
@sktylist2[ @acctnum ] += value
end

p @sktylist1
p @sktylist2

regards,

Siep

Tim W. wrote:

Craig D. wrote:

I posted some code just before you replied. Did it help?

I did not store anything when I run it with my code I posted I get:

{}
{}
{}

Hash.new { |hash, key| hash[key] = Array.new }

Is what you will need if you intend to provide arrays as default values
to hashes.

So… (I’ve only skimmed your code, but I think I get the gist of your
idea, so pardon if this isn’t what you were asking for)

Basically, store the raw values, then you can sum and do any number of
operations on them as you wish.

account_balances = Hash.new do |hash, key|
hash[key] = Array.new
end

array_of_accounts.each do |account|
accounts[account_name] << account.this_charge
accounts[account_name] << account.that_charge

end

I’m going to say ab in place of account_balances here…

ab[some_account].sum # if using Rails, else try inject

ab[some_account.inject(BigDecimal.new) do |sum, amount|
sum += amount
end

Siep K. wrote:

Craig D. wrote:

Looks like you forgot to change this line

sktylist = Hash.new("")

to

sktylist = Hash.new( [] )

which makes the default value for new elements an empty array instead of
a
string. Only then can you use the << operator to push values on to the
array.

Regards,
Craig

You mean the block form: Hash.new{ [] }
Tim, you don’t have to do classes.

f = Info.new(“SKTYFutBalances20080415.txt”)
@sktylist1 = Hash.new{ [] } #with curly braces
@sktylist2 = Hash.new(0)
f.each do |list|

parsing stuff here

@sktylist1[ @acctnum ] = @sktylist1[ @acctnum ] << value
@sktylist2[ @acctnum ] += value
end

p @sktylist1
p @sktylist2

regards,

Siep

Siep,

I worked with your code and its giving me the same thing I had before,
below is the output of the script. What I need to do is for example is
the account number 740 is to store it as key 740 and the value is the
sum of the balances listed. So where there is the account number listed
more than once it uses that account number and balance and moves on to
the next line and if that account number is not in the has it puts a new
account number with its balance. Hope this help make a little more
sense of what I’m trying to do.

{“700”=>[2876.86]}
{“701”=>[654.18]}
{“702”=>[47.74]}
{“705”=>[-22.26]}
{“707”=>[-120.0]}
{“708”=>[502.63]}
{“711”=>[394.13]}
{“712”=>[210.51]}
{“740”=>[7334.36]}
{“740”=>[-12430.14]}
{“740”=>[0.0]}
{“741”=>[14740.47]}
{“741”=>[44919.21]}
{“741”=>[-1009.83]}
{“742”=>[-385.35]}
{“744”=>[-2994.75]}
{“745”=>[-152.86]}

Tim W. wrote:

Siep K. wrote:
Siep,

I worked with your code and its giving me the same thing I had before,
below is the output of the script. What I need to do is for example is
the account number 740 is to store it as key 740 and the value is the
sum of the balances listed. So where there is the account number listed
more than once it uses that account number and balance and moves on to
the next line and if that account number is not in the has it puts a new
account number with its balance. Hope this help make a little more
sense of what I’m trying to do.

{“700”=>[2876.86]}
{“701”=>[654.18]}
{“702”=>[47.74]}
{“705”=>[-22.26]}
{“707”=>[-120.0]}
{“708”=>[502.63]}
{“711”=>[394.13]}
{“712”=>[210.51]}
{“740”=>[7334.36]}
{“740”=>[-12430.14]}
{“740”=>[0.0]}
{“741”=>[14740.47]}
{“741”=>[44919.21]}
{“741”=>[-1009.83]}
{“742”=>[-385.35]}
{“744”=>[-2994.75]}
{“745”=>[-152.86]}

You’re creating a different hash for every line. You probably want one
hash, looking like this:
{700=>2876.86, 701=>654.18, …}
I guess you have a Hash.new somewhere in your do-end block. (it should
be before the block) Also you are probably printing the hash inside the
block. Try it after the block.

@sktylist1 = Hash.new{[]} @sktylist2 = Hash.new(0) DATA.each do|line| temp = line.chomp.split(",") acctnum = temp[0] value = temp[1].to_f @sktylist1[acctnum] = @sktylist1[acctnum] <<value @sktylist2[acctnum] += value end

p @sktylist1
p @sktylist2

END
1234,700.00
5678,-50.00
1234,12.00
8912,35.00
5678,50.00

On Wed, May 7, 2008 at 3:44 PM, Siep K. [email protected]
wrote:

Tim W. wrote:

Did you have a look at the code I posted a few weeks ago for this?

http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/c01af1814e46cc08?fwc=2

Tim W. wrote:

I worked with your code and its giving me the same thing I had before,
below is the output of the script. What I need to do is for example is
the account number 740 is to store it as key 740 and the value is the
sum of the balances listed. So where there is the account number listed
more than once it uses that account number and balance and moves on to
the next line and if that account number is not in the has it puts a new
account number with its balance. Hope this help make a little more
sense of what I’m trying to do.

{“700”=>[2876.86]}
{“701”=>[654.18]}

Could you use Hash#collate (together with an Array#sum method) for this?

http://snippets.dzone.com/posts/show/4930

Cheers,

j.k.