开发者

How do you narrow down a series of arrays?

I have several arrays. And I want to narrow them down, so that at the end, whatever comes out, are values that are seen in all of the other arrays so long as those arrays are not nil.

My sad attempt at coding:

array_of_users = []
array_of_users & @zip_ids if !@zip_ids.empty?
array_of_users & @sex_ids if !@sex_ids.empty?
array_of_users & @interest_ids if !@interest_ids.empty?
array_of_users & @age_ids if !@age_ids.empty?

Logically, I would think this would work because its finding the similarity in each one so long as its not empty, but it doesn't actually add the开发者_StackOverflowm to the array.

How would you accomplish this?


I think you want this:

users = [@zip_ids,@sex_ids,@interest_ids,@age_ids].reject(&:empty?).reduce(&:&)


Think about it this way:

([1] | [2] | [3,4]) & [3,4]

=> [3,4]

So you could do:

array_of_users = @zip_ids | @sex_ids | @interest_ids | @age_ids

intersection = array_of_users & @zip_ids & @sex_ids & @interest_ids & @age_ids

Only, like @glenn says, it ignores the "dont merge if empty" requirement.

@DigitalRoss is good, but if the first array is empty, it all goes flat.

Favorite, then, from @glenn:

[[],[1,2],[2],[2,3,4,4],[]].reject(&:empty?).reduce(&:&)

=> [2]


You need to actually assign them to the array. At the point your code is sitting at, you're doing the intersection, but you're not actually assigning them to the array. You need to add ='s operators in there.

Here is an example setup:

>> x = [ 1, 1, 3, 5 ] 
>> y = [ 1, 2, 3 ]

This is what you're doing right now:

>> x & y
=> [1, 3]
>> x
=> [1, 1, 3, 5]

This is where it needs to go:

>> x &= y
=> [1, 3]
>> x
=> [1, 3]

Thus, this should get the job done:

array_of_users = []
array_of_users &= @zip_ids if !@zip_ids.empty?
array_of_users &= @sex_ids if !@sex_ids.empty?
array_of_users &= @interest_ids if !@interest_ids.empty?
array_of_users &= @age_ids if !@age_ids.empty?

Hope this helps- Sidenote: I did all of this in IRB (interactive ruby shell). It's your friend. :)


[@z, @s, @i, @a].reject(&:empty?).inject { |m, e| m & e }


As you can read here the method Array#& returns a NEW Array and does not modify the original one, so you would have to change your code to something like:

Assuming you want the IDs that are contained in all the four arrays that are not empty, I would try something like this:

ary = []
ids = [@zip_ids, @sex_ids, @interest_ids, @age_ids]
ids.each {|i|ary << i unless i.empty?}
ary.uniq!
result = ids.inject(ary){|res, ids| res & ids}


As Glenn suggests, the most idiomatic way to do this is probably

users = [@zip_ids, @sex_ids, @interest_ids, @age_ids].reject(&:empty?).reduce(&:&)

However, this depends on the behavior of #hash and #eql? for the objects in the array. Since the implementation of Object#hash is based on object_id, Array#& for User objects (presumably using the default Object#hash impl) will compare object ids, not whatever values define equality semantics for your object.

A solution that allows you to compare arrays of User objects rather than just their ids would be to define #hash and #eql? semantics for your object and then use Array#&. For instance:

class User
  # ...

  def hash
    [self.class, *equality_attributes].map(&:hash).reduce(:^)
  end

  def eql?(other)
    self.class == other.class &&
      self.equality_attributes == other.equality_attributes
  end

  # ...

  private

  def equality_attributes
    [name, address]
  end
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜