简体   繁体   中英

How can I improve this Array.select in Ruby?

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM