合并两个基于外键的数组

时间:2016-12-25 19:37:50

标签: ruby-on-rails ruby

我有一个搜索功能,可以查找两个模型AB。结果为@a@b。两者都包含manufacturer_idmodel_id

@a = [
  #<A id: 6, manufacturer_id: 1, model_id: 6, front: 30, side: 39, rear: 19, roof: 0, created_at: "2016-12-17 23:34:58", updated_at: "2016-12-17 23:34:58">,
  #<A id: 10, manufacturer_id: 1, model_id: 10, front: 30, side: 39, rear: 19, roof: 0, created_at: "2016-12-17 23:34:58", updated_at: "2016-12-17 23:34:58">
]
@b = [
  #<B id: 167, manufacturer_id: 1, model_id: 6, FL_1: 30, FL_2: 24, FR_1: 30, FR_2: 24, FC_1: 0, FC_2: 0, RL_1: 22, RL_2: 24, RR_1: 22, RR_2: 24, RC_1: 20, RC_2: 11, third_1: 0, third_2: 0, forth_1: 0, forth_2: 0, boot_1: 0, boot_2: 0, total: 60, created_at: "2016-12-17 23:35:10", updated_at: "2016-12-17 23:35:10">,
  #<B id: 175, manufacturer_id: 1, model_id: 10, FL_1: 28, FL_2: 22, FR_1: 28, FR_2: 22, FC_1: 0, FC_2: 0, RL_1: 26, RL_2: 22, RR_1: 26, RR_2: 22, RC_1: 12, RC_2: 18, third_1: 0, third_2: 0, forth_1: 0, forth_2: 0, boot_1: 0, boot_2: 0, total: 44, created_at: "2016-12-17 23:35:10", updated_at: "2016-12-17 23:35:10">
]

我正在尝试根据manufacturer_idmodel_id合并两个数组。预期结果是:

@output = [#<A id: 6, B id: 167, manufacturer_id: 1, model_id: 6>], #<A id: 10, B id: 175, manufacturer_id: 1, model_id: 10>]

在我看来,我的结果应该仍然能够引用manufacturermodel模型并获取特定参数。

<% @output.each do |r| %>
  <tr>
    <td><%= r.manufacturer.name %></td>
    <td><%= link_to r.model.name, edit_model_path(r) %></td>
    <td colspan=2>
        <%= link_to "View", a_path(r), class: "button btn btn-success btn-xs" %> 
        <%= link_to "Edit", edit_b_path(r), class: "button btn btn-warning btn-xs" %>
    </td>
    <td colspan=2>
        <%= link_to "View", b_path(r), class: "button btn btn-success btn-xs" %> 
        <%= link_to "Edit", edit_b_path(r), class: "button btn btn-warning btn-xs" %>
    </td>
  </tr>
<% end %>

我发现我可以使用id加入他们两个。但是,我不知道如何根据公共/外键id加入它们。

我尝试了这个,但它没有做到这一点:

outputs = (@a+@b).group_by{|h| h[:manufacturer_id]}.map{|k,v| v.reduce(:merge)}

请指导我。

2 个答案:

答案 0 :(得分:2)

您可以使用group_byset intersection查找包含常见ID的对象。

更新:现在使用set union来输出每个id组合。

@a = [
  { id: 6, manufacturer_id: 1, model_id: 6 },
  { id: 10, manufacturer_id: 1, model_id: 10 },
  { id: 111, manufacturer_id: 3, model_id: 4 }
]

@b = [
  { id: 167, manufacturer_id: 1, model_id: 6 },
  { id: 175, manufacturer_id: 1, model_id: 10 },
  { id: 176, manufacturer_id: 2, model_id: 3 }
]

def group_by_ids(array)
  array.group_by { |h| h.values_at(:manufacturer_id, :model_id) }
end

a_by_ids = group_by_ids(@a)
b_by_ids = group_by_ids(@b)

common_keys = a_by_ids.keys & b_by_ids.keys
all_keys    = a_by_ids.keys | b_by_ids.keys

result = all_keys.map do |ids|
  a_objects = a_by_ids[ids]
  b_objects = b_by_ids[ids]
  a_object  = a_objects && a_objects.first
  b_object  = b_objects && b_objects.first
  [*ids, a_object, b_object]
end

输出:

[[1,
  6,
  {:id=>6, :manufacturer_id=>1, :model_id=>6},
  {:id=>167, :manufacturer_id=>1, :model_id=>6}],
 [1,
  10,
  {:id=>10, :manufacturer_id=>1, :model_id=>10},
  {:id=>175, :manufacturer_id=>1, :model_id=>10}],
 [3, 4, {:id=>111, :manufacturer_id=>3, :model_id=>4}, nil],
 [2, 3, nil, {:id=>176, :manufacturer_id=>2, :model_id=>3}]]

所以你得到一个数组数组,每个子数组看起来像:

[manufacturer_id, model_id, a_object, b_object]

您可能需要稍微调整一下视图,但每个数组中应该有足够的信息。

答案 1 :(得分:2)

这是另一种方法。

[@a, @b].flatten.group_by do |row|
  row.values_at(:manufacturer_id, :model_id)
end.reduce([]) do |output, ((manufacturer_id, model_id), data)|
  output << data.reduce({}) { |memo, x| memo.merge(x) }
end

如果您需要进行任何类型的重命名以防止哈希值发生冲突,您可以修改传递给data.reduce的块以进行更细微的merge