【问题标题】:How to combine arrays of similar data in Ruby?如何在 Ruby 中组合相似数据的数组?
【发布时间】:2011-12-29 22:03:32
【问题描述】:

我正在开发一个可以比较两个 .csv 文件的程序。从一个 csv 文件中提取相关数据到一个数组数组中后,我需要合并相关条目。比如我想转这个数组:

[["11/13/15", ["4001", "1392"], "INBOUND"], 
["11/13/15", ["4090", "540"], "INBOUND"], 
["11/13/15", ["1139", "162"], "INBOUND"], 
["11/13/15", ["1158", "64"], "INBOUND"], 
["11/13/15", ["4055", "352"], "OUTBOUND"], 
["11/13/15", ["4055", "448"], "OUTBOUND"], 
["11/13/15", ["4055", "352"], "OUTBOUND"], 
["11/13/15", ["1139", "162"], "OUTBOUND"], 
["11/13/15", ["1158", "64"], "OUTBOUND"], 
["11/13/15", ["4091", "520"], "OUTBOUND"]]

进入这个:

[["11/13/15", ["4001", "1392"], "INBOUND"], 
["11/13/15", ["4090", "540"], "INBOUND"], 
["11/13/15", ["1139", "162"], "INBOUND"], 
["11/13/15", ["1158", "64"], "INBOUND"], 
["11/13/15", ["4055", "1152"], "OUTBOUND"], 
["11/13/15", ["1139", "162"], "OUTBOUND"], 
["11/13/15", ["1158", "64"], "OUTBOUND"], 
["11/13/15", ["4091", "520"], "OUTBOUND"]]

对于数组的某些元素,如果它在[0][1][0][2] 的项与另一个元素匹配,则创建一个新项(数组),其在[1][1] 的项为总和[1][1] 的所有项目并删除旧数组。如果更简单,我可以更改提取相关数据的方式,使[1] 处的项目不是数组,并且每行有 4 个项目而不是 3 个。

【问题讨论】:

  • 那些元素是连续的吗?
  • 数据将被排序,以便在打印时看起来像顶部数组,所以是的(如果我理解你的问题)。
  • 假设 tokland 的答案确实是您想要的,那么您的问题在结果数组的 [4][1][1] 处的值有错字,这是唯一的关键值。应该是 1152,而不是 1115。我必须说你的问题很草率。
  • @sawa 没有注意到那个错字。也感谢您帮助澄清我的句子。

标签: ruby arrays csv


【解决方案1】:

我假设要分组的元素是连续的,所以我们可以使用Enumerable#chunk。函数式方法:

grouped_xs = xs.chunk { |date, (id1, id2), direction| [date, id1, direction] }
grouped_xs.map do |(date, id1, direction), ary|
  id2_sum = ary.map { |date, (id1, id2), direction| id2.to_i }.inject(:+)
  [date, id1, id2_sum.to_s, direction]
end

输出(你想要输出数组中有 4 个元素,对吗?):

[["11/13/15", "4001", "1392", "INBOUND"],
 ["11/13/15", "4090", "540", "INBOUND"],
 ["11/13/15", "1139", "162", "INBOUND"],
 ["11/13/15", "1158", "64", "INBOUND"],
 ["11/13/15", "4055", "1152", "OUTBOUND"],
 ["11/13/15", "1139", "162", "OUTBOUND"],
 ["11/13/15", "1158", "64", "OUTBOUND"],
 ["11/13/15", "4091", "520", "OUTBOUND"]]

【讨论】:

  • @Sean:不客气。作为一般建议,我认为最好不要急于选择答案,有人可能会提出更好的解决方案:-)
  • 那是一些非常紧凑的 Ruby @tokland :)
  • @SeanVikoren:功能解决方案往往非常紧凑。有时它们比命令式的更难阅读,但从概念上讲它们非常好(比如将乐高积木放在一起,而不是从头开始构建所有东西)。
  • @tokland 我会在以后的问题中记住这一点(我相信我会有很多问题)。
  • @tokland:它确实有一种迷人的美感。
【解决方案2】:

仅举个例子 - 我的单线(适用于 1.8 和 1.9 rubies):

table = [["11/13/15", ["4001", "1392"], "INBOUND"], 
["11/13/15", ["4090", "540"], "INBOUND"], 
["11/13/15", ["1139", "162"], "INBOUND"], 
["11/13/15", ["1158", "64"], "INBOUND"], 
["11/13/15", ["4055", "352"], "OUTBOUND"], 
["11/13/15", ["4055", "448"], "OUTBOUND"], 
["11/13/15", ["4055", "352"], "OUTBOUND"], 
["11/13/15", ["1139", "162"], "OUTBOUND"], 
["11/13/15", ["1158", "64"], "OUTBOUND"], 
["11/13/15", ["4091", "520"], "OUTBOUND"]]

result = table.group_by {|a, (b, c), d| [a, [b], d]}.map {|k, v| k[1] << v.map {|a| a[1][1].to_i}.inject(:+).to_s; k}

【讨论】:

  • 我特别喜欢“group_by {|a, (b, c), d|” - 非常好。
【解决方案3】:

应该这样做:

def lookup(list, id, direction)
  index = nil
  list.each_with_index do |e, i|
    if (id == e[1][0]) and (e[2] == direction)
      index = i
      break
    end
  end
  index
end

b = []

a.each do |e|
  id = e[1][0]
  direction = e[2]
  i = lookup(b, id, direction)
  if i.nil?
    b << e
  else
    count = e[1][1].to_i
    sum = count + b[i][1][1].to_i
    b[i][1][1] = sum.to_s
  end
end

b.each{|e| p e}

输出:

["11/13/15", ["4001", "1392"], "INBOUND"]
["11/13/15", ["4090", "540"], "INBOUND"]
["11/13/15", ["1139", "162"], "INBOUND"]
["11/13/15", ["1158", "64"], "INBOUND"]
["11/13/15", ["4055", "1152"], "OUTBOUND"]
["11/13/15", ["1139", "162"], "OUTBOUND"]
["11/13/15", ["1158", "64"], "OUTBOUND"]
["11/13/15", ["4091", "520"], "OUTBOUND"]

【讨论】:

    【解决方案4】:
    h = Hash.new(0)
    [["11/13/15", ["4001", "1392"], "INBOUND"], 
    ["11/13/15", ["4090", "540"], "INBOUND"], 
    ["11/13/15", ["1139", "162"], "INBOUND"], 
    ["11/13/15", ["1158", "64"], "INBOUND"], 
    ["11/13/15", ["4055", "352"], "OUTBOUND"], 
    ["11/13/15", ["4055", "448"], "OUTBOUND"], 
    ["11/13/15", ["4055", "352"], "OUTBOUND"], 
    ["11/13/15", ["1139", "162"], "OUTBOUND"], 
    ["11/13/15", ["1158", "64"], "OUTBOUND"], 
    ["11/13/15", ["4091", "520"], "OUTBOUND"]]
    .each{|a, (b, c), d| h[[a, b, d]] += c.to_i}
    p h.map{|(a, b, d), c| [a, [b, c], d]}
    

    将给予:

    [["11/13/15", ["4001", 1392], "INBOUND"],
    ["11/13/15", ["4090", 540], "INBOUND"],
    ["11/13/15", ["1139", 162], "INBOUND"],
    ["11/13/15", ["1158", 64], "INBOUND"],
    ["11/13/15", ["4055", 1152], "OUTBOUND"],
    ["11/13/15", ["1139", 162], "OUTBOUND"],
    ["11/13/15", ["1158", 64], "OUTBOUND"],
    ["11/13/15", ["4091", 520], "OUTBOUND"]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      • 2020-01-28
      • 1970-01-01
      • 2018-07-27
      • 2013-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多