Convert Array to nested Hash

Discussion in 'Ruby' started by Zhi-Qiang Lei, Oct 24, 2010.

  1. 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.
    Zhi-Qiang Lei, Oct 24, 2010
    #1
    1. Advertising

  2. On Oct 24, 2010, at 7:25 AM, Zhi-Qiang Lei wrote:

    > 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
    --
    Sandor Szuecs, Oct 24, 2010
    #2
    1. Advertising

  3. On Sun, Oct 24, 2010 at 11:27 AM, Sandor Szuecs
    <> 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:
    >>
    >> [
    >> =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/
    Robert Klemme, Oct 24, 2010
    #3
  4. On Oct 24, 2010, at 7:07 PM, Robert Klemme wrote:

    > On Sun, Oct 24, 2010 at 11:27 AM, Sandor Szuecs
    > <> wrote:
    >>=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.=
    Zhi-Qiang Lei, Oct 24, 2010
    #4
  5. [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.
    Adam Prescott, Oct 24, 2010
    #5
  6. On Oct 25, 2010, at 12:02 AM, Adam Prescott wrote:

    >>
    >> A beautiful injecting
    >>

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


    I agree.
    Zhi-Qiang Lei, Oct 24, 2010
    #6
  7. Zhi-Qiang Lei

    w_a_x_man Guest

    On Oct 24, 6:07 am, Robert Klemme <> wrote:

    >
    > 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}
    w_a_x_man, Oct 24, 2010
    #7
  8. On Oct 24, 2010, at 7:07 PM, Robert Klemme wrote:

    > On Sun, Oct 24, 2010 at 11:27 AM, Sandor Szuecs
    > <> wrote:
    >>=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
    Zhi-Qiang Lei, Nov 5, 2010
    #8
  9. On Nov 5, 2010, at 10:58 AM, Zhi-Qiang Lei wrote:
    > On Oct 24, 2010, at 7:07 PM, Robert Klemme wrote:
    > On Sun, Oct 24, 2010 at 11:27 AM, Sandor Szuecs
    >> <> 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
    >>
    >> --
    >> remember.guy do |as, often| as.you_can - without end
    >> http://blog.rubybestpractices.com/
    >>

    >
    >
    > 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
    >


    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
    http://AgileConsultingLLC.com/
    http://GaslightSoftware.com/
    Rob Biedenharn, Nov 5, 2010
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. rp
    Replies:
    1
    Views:
    512
    red floyd
    Nov 10, 2011
  2. Anthony Martinez
    Replies:
    4
    Views:
    267
    Robert Klemme
    Jun 11, 2007
  3. Michal Suchanek
    Replies:
    6
    Views:
    224
    Nobuyoshi Nakada
    Jun 13, 2007
  4. Srijayanth Sridhar
    Replies:
    19
    Views:
    608
    David A. Black
    Jul 2, 2008
  5. dt

    convert string to hash of hash?

    dt, Mar 1, 2007, in forum: Perl Misc
    Replies:
    1
    Views:
    462
    ~greg
    Mar 2, 2007
Loading...

Share This Page