简体   繁体   中英

In Rails, how do I figure out if an array of objects contains specific attributes matching given values?

I'm using Ruby on Rails 5.0.1 with Ruby 2.4. I have an array of objects, stored in the array, "results." Each object has a numeric attribute

numeric_attr

I would like to know, given my array, how I can tell if I have exactly one object with a numeric attribute value of "1" and incrementing by one. Order is not important. So, for instance, if I have an array of three objects,

[MyObject(numeric_attr = 2), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]

I want to know if I have exactly one object with numeric_attr = 1, another object with numeric_attr = 2, and another with numeric_attr = 3. So the above satisfies the condition. The below example does not

[MyObject(numeric_attr = 4), MyObject(numeric_attr = 1), MyObject(numeric_attr = 3)]

because although there is an object with numeric_attr = 1, there is no object with numeric_attr = 2. It is possible thet the numeric_attr field is nil. How can I figure this out?

This one-liner should work:

results.map(&:numeric_attr).sort == (1..results.count).to_a

Explanation:

results
#=> [#<MyObject:... @attr=2>, #<MyObject:... @attr=3>, #<MyObject:... @attr=1>]

results.map(&:attr)
#=> [2, 3, 1]

results.map(&:attr).sort
#=> [1, 2, 3]

(1..results.length).to_a
#=> [1, 2, 3]

# therefore:
results.map(&:attr).sort == (1..results.count).to_a
#=> true

If there is a chance that numeric_attr is nil :

results.map(&:attr).compact.sort == (1..results.count).to_a

Of course, if there is even a single nil value, the result is guaranteed to be false .

If the sequence could start at any number, not just 1:

results.map(&:attr).sort == results.count.times.to_a.
  map { |i| i + results.map(&:attr).sort.first }

This is not very efficient though, as it sorts the numbers twice.

If they always start at 1 @Máté's solution works, if they can start at any arbitrary number then you could:

count = 0
array_objects.sort_by(&:numeric_attr).each_cons(2) {|a,b| count+=1 if a.numeric_attr==b.numeric_attr-1 }
count+1==array_objects.count

Not as elegant but handles a lot more situations

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