Как найти записи из объекта массива на основе значений другого массива в ruby - PullRequest
0 голосов
/ 11 июня 2018

Допустим, у нас есть массив, содержащий идентификаторы объектов, которые необходимо извлечь

Это идентификаторы, которые необходимо извлечь из другого массива объектов

`idvalues=[2,3]`

Это массив объектов

 array_object=[#<CustomPricing id: 2, base_price: 500>, #<CustomPricing id: 3, base_price: 700>, #<CustomPricing id: 4, base_price: 900>, #<CustomPricing id: 2, base_price: 500>]

Как мы можем получить объекты с помощью id's 2 & 3 и поместить их в новый массив.Здесь также есть несколько записей с одним и тем же идентификатором, поэтому просто хочу только первую запись.

Я пробовал вот так

events = idvalues.each {|id_value| array_object.find(id=id_value)}

, но это вернуло idvalue, что [2,3].Как мы можем достичь этого?

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

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

Код

require 'set'

def extract(array_object, id_values)
  idv = id_values.to_set
  arr = []
  array_object.each do |obj|
    id = obj[:id]
    if idv.include?(id)
      arr << obj
      idv.delete(id)
    end
    break if idv.empty?
  end 
  idv.empty? ? arr : nil
end

Пример

id_values = [2, 3]

CustomPricing = Struct.new(:id, :base_price) {}
array_object = [[3, 700], [2, 500], [4, 900], [2, 500]].map do |id, bp|
  CustomPricing.new(id, bp)
end
  #=> [#<struct CustomPricing id=3, base_price=700>,
  #    #<struct CustomPricing id=2, base_price=500>,
  #    #<struct CustomPricing id=4, base_price=900>,
  #    #<struct CustomPricing id=2, base_price=500>]

Читатели, незнакомые со структурами (или нуждающиеся в зачистке), могут захотеть прочитать эту статью .

extract(array_object, id_values)
  #=> [#<struct CustomPricing id=3, base_price=700>,
  #    #<struct CustomPricing id=2, base_price=500>]

Если объекты упорядочены по значениям :id, отражающим их порядок в id_values, предпоследнюю строку (idv.empty? ? arr : nil) можно заменить следующим:

idv.empty? ? arr.sort_by { |obj| id_values.index(obj[:id]) } : nil

, который выдает следующее возвращаемое значение.

[#<struct CustomPricing id=2, base_price=500>,
 #<struct CustomPricing id=3, base_price=700>]
0 голосов
/ 11 июня 2018

Одним из решений будет:

grouped = array_object.group_by(&:id)
selected = idvalues.uniq.map { |id| grouped[id].first }

(uniq может быть удален, если массив idvalues ​​не содержит дубликатов)

Или другая версия

selected = array_object.group_by(&:id).values_at(*id_values).map(&:first)

(см. комментарий @mudasobwa к этому ответу)

Сначала группируются цены по id, а затем используется map, чтобы найти сопоставление идентификаторов с первой ценой с этим идентификатором.

Но комментарий @mudasobwa к вашему вопросу показывает более простой способ решить эту проблему:

selected = idvalues.map {|id| array_object.find { |o| o.id == id} }

Остается вопрос: почему array_object даже содержит повторяющиеся цены?

Если онибыли уникальными, вы могли просто использовать select:

selected = array_object.select { |pricing| idvalues.includes?(pricing.id) }

Вы могли бы сначала сделать массив uniq:

selected = array_object.select { |pricing| idvalues.includes?(pricing.id) }

(если объекты в массиве имеют соответствующий реализованный оператор равенства)

Но, честно говоря, я думаю, что в первую очередь массив не должен содержать повторяющихся элементов.Это звучит как запрос, который можно оптимизировать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...