如何根据ruby

时间:2018-06-11 18:24:13

标签: ruby-on-rails ruby

假设我们有一个包含需要提取的对象ID的数组

这是需要从另一个对象数组

获取的ID
`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&amp; 3并将它们放入新数组中。这里也有多个具有相同id的记录,所以只想要第一条记录。

我试过这个

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

但这会返回idvalue本身[2,3]。我们怎样才能做到这一点?

2 个答案:

答案 0 :(得分:3)

一种解决方案是:

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

(如果idvalues数组不包含任何重复项,则可以删除uniq)

或其他版本

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

(见@mudasobwa对此答案的评论)

首先按id对价格进行分组,然后使用map查找ID与具有该ID的第一个定价的映射。

但@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) }

(如果数组中的对象实现了正确的相等运算符)

但老实说,我认为数组首先不应包含重复的项目。这听起来像一个可以优化的查询?

答案 1 :(得分:1)

这是一种从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>]

不熟悉结构(或需要刷新)的读者可能希望阅读this article

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>]