# Turning an Array into a Hash based on an attribute value

**URL:** <https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179>\
**Category:** Ruby\
**Created:** [June 22, 2006, 8:52pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179 "2006-06-22T20:52:43Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 8:52pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/1 "2006-06-22T20:52:43Z")

</div>

A guy I work with has some some work on an ActiveRecord class that  
basically reads static lookup data, and contains (among other things)  
an “identifier” attribute. Given an array of all these objects he  
wanted to access them by the contents of the identifier attribute, eg:

data\_items = DataItem.find(:all)

# data\_items[3].identifier =\> “my\_identifier”

data\_items[:my\_identifier].do\_something # =\> data\_items[3].do\_something

The best I can come up with is this:

class Array  
def hash\_on(method)  
method = method.to\_sym  
hash = { }  
self.each do |i|  
hash[i.send(method).to\_s.to\_sym] = i  
end  
hash  
end  
end

> [1, “2”, :three].hash\_on(:class)  
> =\> {:String=\>“2”, :Symbol=\>:three, :Fixnum=\>1}

Is there a neater (one-line?) way I missed?

Ashley

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:08pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/2 "2006-06-22T21:08:26Z")

</div>

On 6/22/06, Ashley M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> data\_items = DataItem.find(:all)
> 
> # data\_items[3].identifier =\> “my\_identifier”
> 
> data\_items[:my\_identifier].do\_something # =\> data\_items[3].do\_something

I think your implementation of this looks pretty reasonable, but the  
above begs the question, why does he want to do this? One would think  
that you’d be better off just asking ActiveRecord for the correct  
object, no?

I’m not sure of the api–i.e.: this is untested–but why not something  
like this:

particular\_item = DataItem.find\_by\_identifer(“my\_identifier”)  
particular\_item.do\_something

This is the sort of thing that databases are good at.

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:02pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/3 "2006-06-22T21:02:02Z")

</div>

Ashley M. wrote:

> Is there a neater (one-line?) way I missed?

How about inject:

[1, “2”, :three].inject({}) { |h, e| h[e.class] = e; h }

🙂

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:12pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/4 "2006-06-22T21:12:03Z")

</div>

$ irb  
irb(main):001:0\> class Array  
irb(main):002:1\> def hash\_on(method)  
irb(main):003:2\>  
Hash[\*self.map{|m|m.send(method).to\_s.to\_sym}.zip(self).flatten]  
irb(main):004:2\> end  
irb(main):005:1\> end  
=\> nil  
irb(main):006:0\> [1, “2”, :three].hash\_on(:class)  
=\> {:String=\>“2”, :Symbol=\>:three, :Fixnum=\>1}  
irb(main):007:0\>

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:11pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/5 "2006-06-22T21:11:36Z")

</div>

Ashley M. wrote:

> Ashley  
> class Array  
> def hash\_on(method)  
> inject({}){|h, i| h.merge({i.send(method).to\_s.to\_sym, i})}  
> end  
> end

cheers

Simon

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:27pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/6 "2006-06-22T21:27:32Z")

</div>

Disclaimer: inject is probably more appropriate, but my solution at  
least looks cooler 😉

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 22, 2006, 9:48pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/7 "2006-06-22T21:48:52Z")

</div>

On Jun 22, 2006, at 8:25 pm, Simen E. wrote:

> Hash[\*self.map{|m|m.send(method).to\_s.to\_sym}.zip(self).flatten]

> Disclaimer: inject is probably more appropriate, but my solution at  
> least looks cooler 😉

Simen… you don’t come from a Perl background do you 😉

On Jun 22, 2006, at 8:09 pm, Simon Kröger wrote:

> class Array  
> def hash\_on(method)  
> inject({}){|h, i| h.merge({i.send(method).to\_s.to\_sym, i})}  
> end  
> end

I like!

On Jun 22, 2006, at 8:05 pm, Louis J Scoras wrote:

> I’m not sure of the api–i.e.: this is untested–but why not something  
> like this:
> 
> particular\_item = DataItem.find\_by\_identifer(“my\_identifier”)  
> particular\_item.do\_something
> 
> This is the sort of thing that databases are good at.

It avoids hitting the database every time - if there are 500 items in  
the list I’d rather get them all out at once than hit the server 500  
times.

Thanks for the replies people.

Incidentally… what is the convention here on CCing posters in  
replies? I come from the FreeBSD lists where it’s normal to CC the  
poster so they don’t have to check the list. But people on Ruby  
lists are really surprised when I do that.

---

<div class="post-metadata">

**Author:** ![Ashley\_M](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/a/a5b964/32.png) [@Ashley\_M](https://www.ruby-forum.com/u/Ashley_M)\
**Post date:** [June 23, 2006, 4:47pm UTC](https://www.ruby-forum.com/t/turning-an-array-into-a-hash-based-on-an-attribute-value/64179/8 "2006-06-23T16:47:49Z")

</div>

2006/6/22, Ashley M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> On Jun 22, 2006, at 8:25 pm, Simen E. wrote:
> 
> > Hash[\*self.map{|m|m.send(method).to\_s.to\_sym}.zip(self).flatten]
> 
> > Disclaimer: inject is probably more appropriate, but my solution at  
> > least looks cooler 😉
> 
> Simen… you don’t come from a Perl background do you 😉

LOL - Could also be awk - because the code looks so awkward. :-))

> On Jun 22, 2006, at 8:09 pm, Simon Kröger wrote:
> 
> > class Array  
> > def hash\_on(method)  
> > inject({}){|h, i| h.merge({i.send(method).to\_s.to\_sym, i})}  
> > end  
> > end
> 
> I like!

I like Robin’s inject solution more - it’s more efficient and avoids  
all those short lived hash objects. Also, I’d put it into Enumerable,  
add a block and provide a list of args instead of the method name  
only:

module Enumerable  
def to\_hash(\*args,&b)  
inject({}) {|h,e| h[b ? b[e] : e.send(\*args)] = e; h}  
end  
end

irb(main):019:0\> %w{foo bar baz}.to\_hash {|x| x[0]}  
=\> {102=\>“foo”, 98=\>“baz”}  
irb(main):020:0\> %w{foo bar baz}.to\_hash(:[], 0)  
=\> {102=\>“foo”, 98=\>“baz”}

# silly example to demonstrate what you cannot do without a block

irb(main):022:0\> %w{foo bar baz}.to\_hash {|x| x.length \* rand(100)}  
=\> {132=\>“bar”, 15=\>“foo”, 186=\>“baz”}

> Incidentally… what is the convention here on CCing posters in  
> replies? I come from the FreeBSD lists where it’s normal to CC the  
> poster so they don’t have to check the list. But people on Ruby  
> lists are really surprised when I do that.

I usually don’t because I assume people are checking thelist anyway -  
and until now nobody has complaint that he / she missed a posting from  
me. 🙂

Kind regards

robert
