Convert Array to nested Hash

Z

Zhi-Qiang Lei

Dear All,

I'm seeking a method to convert an array like:

[
["A", "a", 1]
["A", "b", 2]
["B", "a", 1]

]

into a hash as follow:
{
{"A" => {"a" => 1, "b" => 2}},
{"B" => {"a" => 1}}
}

Do you have any idea on this? Thanks in advance.
 
S

Sandor Szuecs

Dear All,
=20
I'm seeking a method to convert an array like:
=20
[
["A", "a", 1]
["A", "b", 2]
["B", "a", 1]
=20
]
=20
into a hash as follow:
{
{"A" =3D> {"a" =3D> 1, "b" =3D> 2}},
{"B" =3D> {"a" =3D> 1}}
}
=20
Do you have any idea on this? Thanks in advance.

I don't think that you really want to add 3 layers of dictionary.
If you really want this, then you think about your abstractions to=20
get a simpler solution.

a =3D [
["A", "a", 1],
["A", "b", 2],
["B", "a", 1]
]
=20
def a_to_h(a)
h=3D{}
a.map do |nested|
key =3D nested.shift
h[key] ||=3D {}
h[key].merge!({ nested.shift =3D> nested.shift })
end =20
h
end

irb:0> a_to_h(a)
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}


All the best, Sandor Sz=FCcs
--
 
R

Robert Klemme

Dear All,

I'm seeking a method to convert an array like:

[
=A0 =A0 =A0 ["A", "a", 1]
=A0 =A0 =A0 ["A", "b", 2]
=A0 =A0 =A0 ["B", "a", 1]

]

into a hash as follow:
{
=A0 =A0 =A0 {"A" =3D> {"a" =3D> 1, "b" =3D> 2}},
=A0 =A0 =A0 {"B" =3D> {"a" =3D> 1}}
}

Do you have any idea on this? Thanks in advance.

I don't think that you really want to add 3 layers of dictionary.
If you really want this, then you think about your abstractions to
get a simpler solution.

=A0a =3D [
=A0 =A0["A", "a", 1],
=A0 =A0["A", "b", 2],
=A0 =A0["B", "a", 1]
=A0]

def a_to_h(a)
=A0h=3D{}
=A0a.map do |nested|
=A0 =A0key =3D nested.shift
=A0 =A0h[key] ||=3D {}
=A0 =A0h[key].merge!({ nested.shift =3D> nested.shift })
=A0end
=A0h
end

irb:0> a_to_h(a)
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}

Here's another way:

irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||=3D {})[k2] =3D v
irb(main):026:1> h
irb(main):027:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}

and another one

irb(main):028:0> [
irb(main):029:1* ["A", "a", 1],
irb(main):030:1* ["A", "b", 2],
irb(main):031:1* ["B", "a", 1],
irb(main):032:1*
irb(main):033:1* ].inject(Hash.new {|h,k|
h[k]=3DHash.new(&h.default_proc)}) do |h,(k1,k2,v)|
irb(main):034:1* h[k1][k2] =3D v
irb(main):035:1> h
irb(main):036:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}

But I totally agree: why build up a strcuture of nested Arrays and
then convert it into the nested Hash structure? Is is much more
efficient to build up the Hash structure initially. One might even
create a Struct for values in the top level Hash.

Cheers

robert

--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
Z

Zhi-Qiang Lei

=20
On Oct 24, 2010, at 7:25 AM, Zhi-Qiang Lei wrote:
=20
Dear All,
=20
I'm seeking a method to convert an array like:
=20
[
["A", "a", 1]
["A", "b", 2]
["B", "a", 1]
=20
]
=20
into a hash as follow:
{
{"A" =3D> {"a" =3D> 1, "b" =3D> 2}},
{"B" =3D> {"a" =3D> 1}}
}
=20
Do you have any idea on this? Thanks in advance.
=20
I don't think that you really want to add 3 layers of dictionary.
If you really want this, then you think about your abstractions to
get a simpler solution.
=20
a =3D [
["A", "a", 1],
["A", "b", 2],
["B", "a", 1]
]
=20
def a_to_h(a)
h=3D{}
a.map do |nested|
key =3D nested.shift
h[key] ||=3D {}
h[key].merge!({ nested.shift =3D> nested.shift })
end
h
end
=20
irb:0> a_to_h(a)
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
Here's another way:
=20
irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||=3D {})[k2] =3D v
irb(main):026:1> h
irb(main):027:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
and another one
=20
irb(main):028:0> [
irb(main):029:1* ["A", "a", 1],
irb(main):030:1* ["A", "b", 2],
irb(main):031:1* ["B", "a", 1],
irb(main):032:1*
irb(main):033:1* ].inject(Hash.new {|h,k|
h[k]=3DHash.new(&h.default_proc)}) do |h,(k1,k2,v)|
irb(main):034:1* h[k1][k2] =3D v
irb(main):035:1> h
irb(main):036:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
But I totally agree: why build up a strcuture of nested Arrays and
then convert it into the nested Hash structure? Is is much more
efficient to build up the Hash structure initially. One might even
create a Struct for values in the top level Hash.
=20
Cheers
=20
robert
=20
--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
=20

A beautiful injecting, thank you all. Because an external library return =
the array, I have to do this.=
 
A

Adam Prescott

[Note: parts of this message were removed to make it a legal post.]
A beautiful injecting

The first solution given is by far the more readable and more
understandable, compared to the injects, I find.
 
W

w_a_x_man

irb(main):019:0> [
irb(main):020:1*   ["A", "a", 1],
irb(main):021:1*   ["A", "b", 2],
irb(main):022:1*   ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1*   (h[k1] ||= {})[k2] = v
irb(main):026:1>   h
irb(main):027:1> end
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}

and another one

irb(main):028:0> [
irb(main):029:1*   ["A", "a", 1],
irb(main):030:1*   ["A", "b", 2],
irb(main):031:1*   ["B", "a", 1],
irb(main):032:1*
irb(main):033:1* ].inject(Hash.new {|h,k|
h[k]=Hash.new(&h.default_proc)}) do |h,(k1,k2,v)|
irb(main):034:1*   h[k1][k2] = v
irb(main):035:1>   h
irb(main):036:1> end
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}


a = [ ["A", "a", 1],
["A", "b", 2],
["B", "a", 1] ]
h = Hash.new{|hash,key| hash[key] = {} }
a.each{|x,y,z| h[x][y] = z}
 
Z

Zhi-Qiang Lei

=20
On Oct 24, 2010, at 7:25 AM, Zhi-Qiang Lei wrote:
=20
Dear All,
=20
I'm seeking a method to convert an array like:
=20
[
["A", "a", 1]
["A", "b", 2]
["B", "a", 1]
=20
]
=20
into a hash as follow:
{
{"A" =3D> {"a" =3D> 1, "b" =3D> 2}},
{"B" =3D> {"a" =3D> 1}}
}
=20
Do you have any idea on this? Thanks in advance.
=20
I don't think that you really want to add 3 layers of dictionary.
If you really want this, then you think about your abstractions to
get a simpler solution.
=20
a =3D [
["A", "a", 1],
["A", "b", 2],
["B", "a", 1]
]
=20
def a_to_h(a)
h=3D{}
a.map do |nested|
key =3D nested.shift
h[key] ||=3D {}
h[key].merge!({ nested.shift =3D> nested.shift })
end
h
end
=20
irb:0> a_to_h(a)
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
Here's another way:
=20
irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||=3D {})[k2] =3D v
irb(main):026:1> h
irb(main):027:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
and another one
=20
irb(main):028:0> [
irb(main):029:1* ["A", "a", 1],
irb(main):030:1* ["A", "b", 2],
irb(main):031:1* ["B", "a", 1],
irb(main):032:1*
irb(main):033:1* ].inject(Hash.new {|h,k|
h[k]=3DHash.new(&h.default_proc)}) do |h,(k1,k2,v)|
irb(main):034:1* h[k1][k2] =3D v
irb(main):035:1> h
irb(main):036:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}
=20
But I totally agree: why build up a strcuture of nested Arrays and
then convert it into the nested Hash structure? Is is much more
efficient to build up the Hash structure initially. One might even
create a Struct for values in the top level Hash.
=20
Cheers
=20
robert
=20
--=20
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
=20


I'm sorry to bring this old topic out. But there is a question make me =
confused.

irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||=3D {})[k2] =3D v
irb(main):026:1> h
irb(main):027:1> end
=3D> {"A"=3D>{"a"=3D>1, "b"=3D>2}, "B"=3D>{"a"=3D>1}}

Is the tuple (k1, k2, v) in block arguments an array? What's the meaning =
of () in block arguments? Thanks.

Best regards,
Zhi-Qiang Lei
(e-mail address removed)
 
R

Rob Biedenharn

On Oct 24, 2010, at 7:07 PM, Robert Klemme wrote:
On Oct 24, 2010, at 7:25 AM, Zhi-Qiang Lei wrote:
Dear All,

I'm seeking a method to convert an array like:

[
["A", "a", 1]
["A", "b", 2]
["B", "a", 1]

]

into a hash as follow:
{
{"A" => {"a" => 1, "b" => 2}},
{"B" => {"a" => 1}}
}

Do you have any idea on this? Thanks in advance.

I don't think that you really want to add 3 layers of dictionary.
If you really want this, then you think about your abstractions to
get a simpler solution.

a = [
["A", "a", 1],
["A", "b", 2],
["B", "a", 1]
]

def a_to_h(a)
h={}
a.map do |nested|
key = nested.shift
h[key] ||= {}
h[key].merge!({ nested.shift => nested.shift })
end
h
end

irb:0> a_to_h(a)
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}

Here's another way:

irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||= {})[k2] = v
irb(main):026:1> h
irb(main):027:1> end
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}

and another one

irb(main):028:0> [
irb(main):029:1* ["A", "a", 1],
irb(main):030:1* ["A", "b", 2],
irb(main):031:1* ["B", "a", 1],
irb(main):032:1*
irb(main):033:1* ].inject(Hash.new {|h,k|
h[k]=Hash.new(&h.default_proc)}) do |h,(k1,k2,v)|
irb(main):034:1* h[k1][k2] = v
irb(main):035:1> h
irb(main):036:1> end
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}

But I totally agree: why build up a strcuture of nested Arrays and
then convert it into the nested Hash structure? Is is much more
efficient to build up the Hash structure initially. One might even
create a Struct for values in the top level Hash.

Cheers

robert


I'm sorry to bring this old topic out. But there is a question make
me confused.

irb(main):019:0> [
irb(main):020:1* ["A", "a", 1],
irb(main):021:1* ["A", "b", 2],
irb(main):022:1* ["B", "a", 1],
irb(main):023:1*
irb(main):024:1* ].inject({}) do |h,(k1,k2,v)|
irb(main):025:1* (h[k1] ||= {})[k2] = v
irb(main):026:1> h
irb(main):027:1> end
=> {"A"=>{"a"=>1, "b"=>2}, "B"=>{"a"=>1}}

Is the tuple (k1, k2, v) in block arguments an array? What's the
meaning of () in block arguments? Thanks.

Best regards,
Zhi-Qiang Lei
(e-mail address removed)[/QUOTE]

The inject() will pass two arguments to the block. The accumulated
value and the new element. In the use of the parentheses in the block
arguments acts like an array assignment so the individual values of
the array element are available with more meaningful names.

inject({}) do |h,array|
k1, k2, v = array
(h[k1] ||= {})[k2] = v
h
end

is the same thing without using the block's ability to "unpack" the
array elements.

-Rob

Rob Biedenharn
(e-mail address removed) http://AgileConsultingLLC.com/
(e-mail address removed) http://GaslightSoftware.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,533
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top