Adding new value (in array) to existing key in a hash


#1

Hi all,

Am new to programming am learning to use ruby to code a program. How do
I add a new value to existing key without overwriting the old value?
Went to documentation, but didn’t find anything that can help me.
Searched on google as well and in vain.

Say I have a value of coordinate [i,j] and am using a hash table to
store these coordinates for a specific location. Let’s say,

Starbuck => [1,2]

How to I append or add a new coordinate of [1,7] to Starbuck? to become,

Starbuck => [1,2], [1,7]

And able to retrieve each individual coordinates later in array as well.
The idea behind the code is iterate, if new location for Starbuck is
found, add the location in i,j format to key “starbuck”.

Thanks a lot for your help.


#2

On 6/16/07, Gilbert L. removed_email_address@domain.invalid wrote:

Starbuck => [1,2]


Posted via http://www.ruby-forum.com/.

If I understood you correctly,
try something like this.

myhash = {}
myhash[“Starbuck”] = []
myhash[“Starbuck”] << [1,2]
myhash[“Starbuck”] << [1,7]

p myhash
p myhash[“Starbuck”][1]
p myhash[“Starbuck”][1][1]

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/


#3

Harry K. wrote:

myhash = {}
myhash[“Starbuck”] = []
myhash[“Starbuck”] << [1,2]
myhash[“Starbuck”] << [1,7]

p myhash
p myhash[“Starbuck”][1]
p myhash[“Starbuck”][1][1]

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/

Thanks a lot. Didn’t know it can be so easy.

Correct me if I am wrong… the = [] means that i initiate the value for
the hash as array first before I input the values as array [i,j] into
the hash. Is that the explanation for the code above?


#4

Thanks a lot. Sorry, got another question

let’s say that the hash is

myhash = {“a” => [[0,0],[3,4]], “b” => [[1,1],[9,8]], “c” => [[7,6]]}

how do I sort the values to become

[0,0],[1,1],[3,4],[7,6],[9,8]

and be able to recall the keys to arrange according to the sorted
values, like

“a”, “b”, “a”, “c”, “b”


#5

On 6/18/07, Gilbert L. removed_email_address@domain.invalid wrote:

and be able to recall the keys to arrange according to the sorted
values, like

“a”, “b”, “a”, “c”, “b”

Well, I think this will work.
Extract the arrays from the values and then sort.

myhash = {“a” => [[0,0],[3,4]], “b” => [[1,1],[9,8]], “c” => [[7,6]]}

arr = []
myhash.each_value do |x|
x.each {|y| arr << y}
end

p arr.sort!

This will find whether it is included in “a” for example

but you need to think about what to do if you have duplicates.

myhash = {“a” => [[0,0],[3,4]], “b” => [[1,1],[0,0],[9,8]], “c” =>

[[7,6]]}

This is ugly but maybe you can get some ideas

arr.each do |c|
p “FROM a” if myhash[“a”].include?©
p “NOT FROM a” unless myhash[“a”].include?©
end

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/


#6

On Behalf Of Gilbert L.:

myhash = {“a” => [[0,0],[3,4]], “b” => [[1,1],[9,8]], “c” => [[7,6]]}

how do I sort the values to become

[0,0],[1,1],[3,4],[7,6],[9,8]

and be able to recall the keys to arrange according to the sorted

values, like

“a”, “b”, “a”, “c”, “b”

just be careful w some value clashes

irb(main):112:0> newhash={}
=> {}
irb(main):113:0> myhash.each{|k,v| v.each{|e| newhash[e]=k}}
=> {“a”=>[[0, 0], [3, 4]], “b”=>[[1, 1], [9, 8]], “c”=>[[7, 6]]}

we create a new hash whose values are now keys

(like invert but your case is special)

so now values still point to their original keys

irb(main):114:0> newhash
=> {[0, 0]=>“a”, [1, 1]=>“b”, [3, 4]=>“a”, [7, 6]=>“c”, [9, 8]=>“b”}
irb(main):118:0> newhash.keys
=> [[0, 0], [1, 1], [3, 4], [7, 6], [9, 8]]
irb(main):119:0> newhash.values
=> [“a”, “b”, “a”, “c”, “b”]
irb(main):120:0>

there is too much magic in there, i’m not sure how/why ruby sorted it
(but i love it :slight_smile:

anyway, just to be sure

irb(main):145:0> newhash.sort_by{|k,v| k}
=> [[[0, 0], “a”], [[1, 1], “b”], [[3, 4], “a”], [[7, 6], “c”], [[9, 8],
“b”]]
irb(main):146:0> newhash.sort_by{|k,v| k}.map{|e| e[0]}
=> [[0, 0], [1, 1], [3, 4], [7, 6], [9, 8]]
irb(main):147:0> newhash.sort_by{|k,v| k}.map{|e| e[1]}
=> [“a”, “b”, “a”, “c”, “b”]

kind regards -botp


#7

Hi –

On Mon, 18 Jun 2007, Harry K. wrote:

This is ugly but maybe you can get some ideas

arr.each do |c|
p “FROM a” if myhash[“a”].include?©
p “NOT FROM a” unless myhash[“a”].include?©
end

One way to generalize it:

arr.sort.map {|c| myhash.keys.find {|k| myhash[k].include?© } }

There’s probably a more efficient way (there usually is when I’m the
first to suggest these things :slight_smile: but that will get you the whole
array.

David


#8

On 6/16/07, Gilbert L. removed_email_address@domain.invalid wrote:

Correct me if I am wrong… the = [] means that i initiate the value for
the hash as array first before I input the values as array [i,j] into
the hash. Is that the explanation for the code above?

Yes, it sets up the value as an array and pushes arrays into that array.
This does the same.

myhash = Hash.new
myhash[“Starbuck”] = Array.new
myhash[“Starbuck”].push([1,2])
myhash[“Starbuck”].push([1,7])

p myhash
p myhash[“Starbuck”][1]
p myhash[“Starbuck”][1][1]

Harry

A Look into Japanese Ruby List in English
http://www.kakueki.com/


#9

Thanks a million. But still I have another problem. Figure that I can
take it on from all your guys’ help, but I can’t.

A more controlled sort. I only want to sort the keys where the values
from myhash follows this pattern of [i,j], [i+1,j+1]… think of it as
a 2-D matrix and I am only interested in the diagonal line. I am not
worried about the duplicates of coordinates, as one coordinates can only
have one occurrence(or building).

For example, the sorted result for the following hash will be:

myhash = {“a”=>[[0, 0], [3, 4]], “b”=>[[1, 1], [9, 8]], “c”=>[[7, 6],[4,
5]}

[[0, 0], [1, 1], [3, 4], [4, 5]]
“a”, “b”, “a”, “c”

Cheers


#10

On 6/18/07, Gilbert L. removed_email_address@domain.invalid wrote:

myhash = {“a”=>[[0, 0], [3, 4]], “b”=>[[1, 1], [9, 8]], “c”=>[[7, 6],[4,
5]}

[[0, 0], [1, 1], [3, 4], [4, 5]]
“a”, “b”, “a”, “c”

Do you mean that [7,6] is not included becuase there is no [6,5] or
[8,7]? You shouldn’t open up core classes and you don’t have to for
this, but it makes it more readable:

class Array
def up; map {|i| i+1}; end
def down; map {|i| i-1}; end
end
h = { “a” => [[0,0],[3,4]], “b” => [[1,1],[9,8]], “c” => [[7,6],[4,5]] }
a = []
h.each_value {|v| v.each {|coord| a << coord}}
end
sorted = a.select {|coord| a.include?(coord.up) ||
a.include?(coord.down) )}.sort

p sorted


#11

On 6/18/07, Todd B. removed_email_address@domain.invalid wrote:

class Array
def up; map {|i| i+1}; end
def down; map {|i| i-1}; end
end
h = { “a” => [[0,0],[3,4]], “b” => [[1,1],[9,8]], “c” => [[7,6],[4,5]] }
a = []
h.each_value {|v| v.each {|coord| a << coord}}

end
^^^ delete the accidental “end” here

sorted = a.select {|coord| a.include?(coord.up) ||
a.include?(coord.down) )}.sort

p sorted

sorry 'bout that


#12

Todd B. wrote:

Do you mean that [7,6] is not included becuase there is no [6,5] or
[8,7]?

Yes. I am only interested in coordinates that fit the pattern of [i, j],
[i+1, j+1]… This is way too advance for me. But thank you guys for all
your help. I learned a lot.