Ruby合并字符串中的重复项

Ruby合并字符串中的重复项,ruby,string,duplicates,concatenation,Ruby,String,Duplicates,Concatenation,如果我有这样一根绳子 str =<<END 7312357006,1.121 3214058234,3456 7312357006,1234 1324958723,232.1 3214058234,43.2 3214173443,234.1 6134513494,23.2 7312357006,11.1 END 7312357006,1246.221 3214058234,3499.2 1324958723,232.1 3214173443,234.1 6134513494,23.

如果我有这样一根绳子

str =<<END
7312357006,1.121
3214058234,3456
7312357006,1234
1324958723,232.1
3214058234,43.2
3214173443,234.1
6134513494,23.2
7312357006,11.1
END
7312357006,1246.221
3214058234,3499.2
1324958723,232.1
3214173443,234.1
6134513494,23.2

如果最终输出是一个数组,这也很好。

您可以使用以下方法实现:

str = "7312357006,1.121
       3214058234,3456
       7312357006,1234
       1324958723,232.1
       3214058234,43.2
       3214173443,234.1
       6134513494,23.2
       7312357006,11.1"

# convert the string into nested pairs of floats
# to briefly summarise the steps: split entries by newline, strip whitespace, split by comma, convert to floats
arr = str.split("\n").map(&:strip).map { |el| el.split(",").map(&:to_f) }

result = arr.each_with_object(Hash.new(0)) do |el, hash| 
  hash[el.first] += el.last
end

# => {7312357006.0=>1246.221, 3214058234.0=>3499.2, 1324958723.0=>232.1, 3214173443.0=>234.1, 6134513494.0=>23.2}

# You can then call `to_a` on result if you want:
result.to_a

# => [[7312357006.0, 1246.221], [3214058234.0, 3499.2], [1324958723.0, 232.1], [3214173443.0, 234.1], [6134513494.0, 23.2]]
each_with_object
迭代每对数据,为它们提供对累加器的访问权(在这里是散列)。通过采用这种方法,我们可以将每个条目添加到散列中,如果它们出现多次,则将总数相加


希望能有所帮助-如果您有任何问题,请告诉我。

在Ruby中有很多方法可以做到这一点。一种特别简洁的方法是使用
String#scan

str = <<END
7312357006,1.121
3214058234,3456
7312357006,1234
1324958723,232.1
3214058234,43.2
3214173443,234.1
6134513494,23.2
7312357006,11.1
END

data = Hash.new(0)
str.scan(/(\d+),([\d.]+)/) {|k,v| data[k] += v.to_f }
p data
# => { "7312357006" => 1246.221,
#      "3214058234" => 3499.2,
#      "1324958723" => 232.1,
#      "3214173443" => 234.1,
#      "6134513494" => 23.2 }
打印结果的方法也有很多,但我喜欢以下几种:

puts data.map {|kv| kv.join(",") }.join("\n")
# => 7312357006,1246.221
#    3214058234,3499.2
#    1324958723,232.1
#    3214173443,234.1
#    6134513494,23.2

# or:
puts data.map {|k,v| "#{k},#{v}\n" }.join
# => (same as above)
你可以


编辑:尽管出于可读性的考虑,我不推荐这两种方法,但这里有更多的方法只是为了提高性能(需要Ruby 2.4+):

…或者,直接转到字符串:

puts str.lines.group_by {|s| s.slice!(/(\d+),/); $1 }
       .map {|k,vs| "#{k},#{vs.sum(&:to_f)}\n" }.join

由于repl.it卡在Ruby 2.3上:

实现了此解决方案,因为哈希给了我一些问题:

d = []
s.split("\n").each do |line|
  x = 0
  q = 0
  dup = false
  line.split(",").each do |data|
    if x == 0 and d.include? data then dup = true ; q = d.index(data) elsif x == 0 then d << data end
    if x == 1 and dup == false then d << data end
    if x == 1 and dup == true then d[q+1] = "#{'%.2f' % (d[q+1].to_f + data.to_f).to_s}" end
    if x == 2 and dup == false then d << data end
    x += 1
  end
end

x = 0
s = ""

d.each do |val|
  if x == 0 then s << "#{val}," end
  if x == 1 then s << "#{val}\n ; x = 0" end
  x += 1
end

puts(s)
d=[]
s、 拆分(“\n”)。每个do |行|
x=0
q=0
dup=假
行。拆分(“,”)。每个do数据|
如果x==0且d.include?然后数据dup=真;q=d.索引(数据)如果x=0,则为d

1语法糖是Ruby允许的快捷方式。

听起来不错,去吧!:-)我相信你不会介意我做的小编辑。通过创建一个有效的字符串对象(您有一个字符串的图片,我认为这是向下投票的原因)并为其分配一个变量,读者可以剪切和粘贴以测试他们的答案,并可以引用该变量(
str
)在回答和注释中,不必定义它。考虑使用<代码>对象> <代码>而不是<代码>减少< /代码>以避免丑陋尾随<代码>哈希< /代码>:<代码> ARR.EACHyth.ObjObjor(hash .New(0)){{el,hash>hash [EL,Field++E..Real}} /Case>。我在使用
reduce
时调用了
hash.tap…
太多次了。谢谢@mudasobwa-更新了我的答案。没有什么值得的。
。map(&:strip)
在这里是必要的,只是因为输入中有前导空格。请参阅我对问题的编辑,它允许您删除
str
的定义。我不得不问。。。为什么
“”。索引(“”
?此外,如果其他答案都不能解决您的问题,您可能应该取消接受您接受的答案(并且,我建议,留下一条评论,描述它是如何不起作用的,这样它的作者可以帮助您解决问题,因为您的解决方案似乎非常复杂).ruby新手,不知道如何保存这样的索引,因为我想在行的不同迭代中调用它。拆分(,“”)。每个
“”。索引(“”)将始终返回
0
,因为空字符串中空字符串的索引总是
0
。我会提供更多数据说明为什么哈希不起作用,但输入确实不应该被共享。我只是将其用作q的占位符,q在循环中被调用,请参阅我对问题的编辑,它允许您删除
str
的定义。
puts str.lines.group_by {|s| s.slice!(/(\d+),/); $1 }
       .map {|k,vs| "#{k},#{vs.sum(&:to_f)}\n" }.join
d = []
s.split("\n").each do |line|
  x = 0
  q = 0
  dup = false
  line.split(",").each do |data|
    if x == 0 and d.include? data then dup = true ; q = d.index(data) elsif x == 0 then d << data end
    if x == 1 and dup == false then d << data end
    if x == 1 and dup == true then d[q+1] = "#{'%.2f' % (d[q+1].to_f + data.to_f).to_s}" end
    if x == 2 and dup == false then d << data end
    x += 1
  end
end

x = 0
s = ""

d.each do |val|
  if x == 0 then s << "#{val}," end
  if x == 1 then s << "#{val}\n ; x = 0" end
  x += 1
end

puts(s)
def combine(str)
  str.each_line.with_object(Hash.new(0)) do |s,h|
    k,v = s.split(',')        
    h.update(k=>v.to_f) { |k,o,n| o+n }
  end.reduce('') { |s,kv_pair| s << "%s,%g\n" % kv_pair }
end 

puts combine str
7312357006,1246.22
3214058234,3499.2
1324958723,232.1
3214173443,234.1
6134513494,23.2
   {"7312357006"=>1246.221, "3214058234"=>3499.2, "1324958723"=>232.1,
    "3214173443"=>234.1, "6134513494"=>23.2}