0

I just wrote this... horrible line of Ruby code, and I'm wondering if there isn't a better way of doing it.

I have an array of hashes, of which I want to fetch one. The "conditions" of what I want to select is in two separate arrays--one with keys and one with values. If a hash in the array has the correct key == value for every pair in keys and values, I want to return that hash.

Any pointers to make the code more readable?

arr = [
  {:foo => 'foo', :bar => 'bar', :baz => 'baz'},
  {:foo => 'bar', :bar => 'bar', :baz => 'bar'},
  {:foo => 'foo', :bar => 'foo', :baz => 'foo'},
]

keys = [:foo, :bar]
values  = ['foo', 'bar']

arr.select{|c| keys.map{|k| i = keys.index(k); c[keys[i]] == values[i]}.delete(false) != false}.first
# => {:foo => 'foo', :bar => 'bar', :baz => 'baz'}
4
  • 1
    I almost never use an array if I'm going to be looking for elements in the collection. I think arrays are great for queues and stacks but I'll use a Hash if I have to find something, or a Hash or a Set if I only want unique values. Commented Nov 24, 2010 at 2:54
  • @Greg, if you never had a deal with smth, it doesn't mean, that it have no sense. Commented Nov 24, 2010 at 3:03
  • I have no idea what you said. Commented Nov 24, 2010 at 4:19
  • Does your last line have to be such a long line? This isn't perl! Commented Nov 24, 2010 at 23:15

2 Answers 2

2

Do you have to specify what you're looking for as an array of keys and an array of values? If you do, then convert them to a Hash like this:

hsh = Hash[*keys.zip(values).flatten]  #=> {:foo=>"foo", :bar=>"bar"}

And then select like this:

arr.select { |c| c == c.merge(hsh) }   #=> [{:foo=>"foo", :bar=>"bar", :baz=>"baz"}]

If you can specify what you're looking for as a Hash in the first place, you don't need the first line.

Sign up to request clarification or add additional context in comments.

4 Comments

Nice! I really like this solution--a lot more elegant than what I've currently got.
Convert them to hash to make solution 2 times shorter and 200 times slower
You're right--the Hash method is slower, but 200x is a bit of an overexaggeration. My benchmarks show about 3x, regardless of size.
@Nakilon, The speed of the program only matters when the program is not fast enough. Until then, it is the speed of the human that matters.
2
arr = [
  {foo:'foo', bar:'bar', baz:'baz'},
  {foo:'bar', bar:'bar', baz:'bar'},
  {foo:'foo', bar:'foo', baz:'foo'},
]

keys = [:foo, :bar]
values = ['foo', 'bar']

p arr.find { |c|
    keys.zip(values).all? { |k,v|
        c[k] == v
    }
}
  1. You can use {foo:'bar'} syntax to declare hashes if you have a symbol as key.
  2. Use Enumerable#find to find first occurence.

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.