繁体   English   中英

红宝石数组单独的“重复项”

[英]ruby array separate “duplicates”

我的单词数组混合了大写字母和非大写字母(有时还有数字):

my_array = ['ZV2', '4Q3', 'abDc', 'zQ2', 'Def', '4q3', 'Abdc', 'ABDC', 'def', 'zv2', 'DeF', 'zV2', 'DEF']

我想分成几个没有重复单词的数组:

my_array1 = ['ZV2', '4Q3', 'abDc', 'zQ2', 'Def']

my_array2 = ['4q3', 'Abdc', 'def', 'zv2']

my_array3 = ['ABDC', 'DeF', 'zV2']

my_array4 = ['DEF']

最好的方法是什么?

问题的参数很容易解释,但是这是一种方法:按值的小写字母对数组进行分组:

> d = my_array.group_by(&:downcase).values
> pp d
[["ZV2", "zv2", "zV2"],
 ["4Q3", "4q3"],
 ["abDc", "Abdc", "ABDC"],
 ["zQ2"],
 ["Def", "def", "DeF", "DEF"]]

这为您提供了一个数组数组,每个数组包含所有重复项。 从这里开始,解决方案应该相对简单:给定该“行”列表,您需要一个“列”列表。 您可以通过创建新的数组来构造输出数组,并获取每个数组的第n个元素,直到没有任何元素。

一种方法(非最佳选择,以防万一,这是家庭作业!)是将所有数组填充到相同的长度,然后转置结果:

d = my_array.group_by(&:downcase).values
max_len = d.map(&:length).max
padded = d.map {|v| v.fill(nil, v.length..max_len) }

pp padded
[["ZV2", "zv2", "zV2", nil, nil],
 ["4Q3", "4q3", nil, nil, nil],
 ["abDc", "Abdc", "ABDC", nil, nil],
 ["zQ2", nil, nil, nil, nil],
 ["Def", "def", "DeF", "DEF", nil]]

现在,您只需转置数组数组并压缩所有nil:

padded.transpose.map(&:compact).select(&:any?)
=> [["ZV2", "4Q3", "abDc", "zQ2", "Def"], ["zv2", "4q3", "Abdc", "def"], ["zV2", "ABDC", "DeF"], ["DEF"]]

这几乎不是最优雅的方法,但是它说明了这个想法。 您也许可以使用它来构想更好的解决方案。

您可以减少数组,在需要时拆分为新的子数组:

my_array.each_with_object([]) do |e, acc|
  (
    acc.find { |a| !a.find { |ae| ae.casecmp(e).zero? } } ||
    (acc << []).last
  ) << e
end
#⇒ [["ZV2", "4Q3", "abDc", "zQ2", "Def"],
#   ["4q3", "Abdc", "def", "zv2"],
#   ["ABDC", "DeF", "zV2"],
#   ["DEF"]]
my_array.each_with_object([]) do |s,a|
  d = s.downcase
  idx = a.find_index { |h| h.key?(d) == false }
  if idx.nil?
    a << { d=>s }
  else
    a[idx][d] = s
  end
end.map(&:values)
  #=> [["ZV2", "4Q3", "abDc", "zQ2", "Def"],
  #    ["4q3", "Abdc", "def", "zv2"],
  #    ["ABDC", "DeF", "zV2"],
  #    ["DEF"]] 

参见Array#find_index

我可以通过添加一些puts语句来最好地解释其工作原理。 有兴趣的读者可以运行下面的代码来观察逐​​步的计算。

arr = my_array.each_with_object([]) do |s,a|
  d = s.downcase
  puts "s=#{s}, a=#{a}, d=#{d}"
  idx = a.find_index { |h| h.key?(d) == false }
  puts "s=#{s}, a=#{a}, idx.nil?=#{idx.nil?}, idx=#{idx}"
  if idx.nil?
    a << { d=>s }
  else
    a[idx][d] = s
  end
  puts "  after case a=#{a.to_s}"
end
arr.map(&:values)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM