Как вы сузите ряд массивов? - PullRequest
0 голосов
/ 04 апреля 2011

У меня есть несколько массивов. И я хочу сузить их, чтобы в конце, что бы ни вышло, были значения, которые видны во всех других массивах, если эти массивы не равны нулю.

Моя грустная попытка кодирования:

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?

Логически, я бы подумал , что это сработает, потому что он находит сходство в каждом из них, пока он не пустой, но фактически не добавляет их в массив.

Как бы вы этого достигли?

Ответы [ 6 ]

2 голосов
/ 04 апреля 2011

Подумайте об этом так:

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

=> [3,4]

Так что вы можете сделать:

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

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

Только, как говорит @glenn, игнорируется требование "не объединять, если пусто"

@ DigitalRoss - это хорошо, но если первый массив пуст, все становится плоским.

Фаворит, затем, из @glenn:

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

=> [2]

2 голосов
/ 04 апреля 2011

Я думаю, вы хотите это:

users = [@zip_ids,@sex_ids,@interest_ids,@age_ids].reject(&:empty?).reduce(&:&)
1 голос
/ 04 апреля 2011
[@z, @s, @i, @a].reject(&:empty?).inject { |m, e| m & e }
1 голос
/ 04 апреля 2011

Вам необходимо назначить их массиву.В тот момент, когда ваш код сидит, вы делаете пересечение, но на самом деле вы не назначаете их массиву.Вам нужно добавить туда операторы =.

Вот пример установки:

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

Это то, что вы делаете прямо сейчас:

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

Это то, куда нужно идти:

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

Таким образом, это должно сделать работу:

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?

Надеюсь, это поможет - Sidenote: Я сделал все это в IRB (интерактивная рубиновая оболочка).Это твой друг.:)

0 голосов
/ 04 апреля 2011

Как предполагает Гленн, самый идиоматический способ сделать это, вероятно,

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

Однако это зависит от поведения #hash и #eql?для объектов в массиве.Поскольку реализация Object # hash основана на object_id, Array # & для пользовательских объектов (предположительно с использованием стандартного Object # hash impl) будет сравнивать идентификаторы объектов, а не любые значения, определяющие семантику равенства для вашего объекта.

AРешение, позволяющее сравнивать массивы объектов User, а не только их идентификаторы, заключается в определении #hash и #eql?семантика для вашего объекта, а затем использовать массив # &.Например:

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 голосов
/ 04 апреля 2011

Как вы можете прочитать здесь метод Array # & возвращает новый массив и не изменяет исходный массив, поэтому вам придется изменить код на что-то вроде:

Предполагая, что вы хотите идентификаторы, содержащиеся во всех четырех непустых массивах, я бы попробовал что-то вроде этого:

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}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...