[英]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.