0

I need a group an array of hashes based on a particular key of each hash. For example, take this:

[
    [0] {
        :status => "pending",
             :x => 1,
             :y => 2
    },
    [1] {
        :status => "pending",
             :x => 33,
             :y => 74
    },
    [2] {
        :status => "done",
             :x => 33,
             :y => 74
    }
]

I need to convert it to this:

{
    "pending" => [
        [0] {
            :status => "pending",
                 :x => 1,
                 :y => 2
        },
        [1] {
            :status => "pending",
                 :x => 33,
                 :y => 74
        }
    ],
       "done" => [
        [0] {
            :status => "done",
                 :x => 33,
                 :y => 74
        }
    ]
}

I am grouping the array by :status key. I have done this (it works):

a.inject({}) {|a, b| (a[b[:status]] ||= []) << b; a }

But, is there a simpler, less cryptic one-liner that can do the same thing?

1
  • 1
    Doesn't your way work? Commented Apr 10, 2013 at 8:00

2 Answers 2

2

Why not use group_by? It does exactly what you need.

a.group_by {|b| b[:status] }
Sign up to request clarification or add additional context in comments.

1 Comment

always think of group_by before you inject each_with_object, i'd say :)
1

It's not a common enough operation to warrant a built-in descriptive method, but I would tweak your line slightly.

Instead of using #inject(), how about using #each_with_object()? It's more appropriate for passing the same object over an iteration, as that's exactly what it does - it's also more descriptive than "inject", IMO.

That has the added benefit of removing the ; a from the end of the block: this is the problem with using inject to pass the same object between each iteration. Therefore, the final line becomes (with some variable name tweaking):

ary.each_with_object({}) {|e, obj| (obj[e[:status]] ||= []) << e }

The return value of each_with_object is the hash that's being built up, so you can assign the above to a variable, or return it from your method.

In the end, if you want it to be more descriptive in your application, wrap that line in a method that is descriptive:

def index_with_status(ary)
    ary.each_with_object({}) {|e, obj| (obj[e[:status]] ||= []) << e }
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.