Ruby中使用索引值识别和更新数组中的重复项

w41d8nur  于 2023-05-17  发布在  Ruby
关注(0)|答案(4)|浏览(86)

我有一个数组,它可能包含也可能不包含重复,但没有nil或“”值。

array = ["Ballerina", "Lagoon", "Black", "Space", "Golden", "Lagoon"]

这真的是我最接近解决这个问题的方法,但问题是我不知道重复的内容,所以它不是真的有效:

array.each_with_index.map {|value, index| array[index] == "Lagoon" ? index : ""}.uniq

我希望返回的是数组中的任何重复项都将索引值连接到数组值的末尾。所以最终的结果是:

array = ["Ballerina", "Lagoon 1", "Black", "Space", "Golden", "Lagoon 5"]

谢谢

7rtdyuoh

7rtdyuoh1#

一种方法是使用Enumerable#tally方法按值存储总计数的散列。

array = ["Ballerina", "Lagoon", "Black", "Space", "Golden", "Lagoon"]

# Generates hash for faster lookup
# {"Ballerina"=>1, "Lagoon"=>2, "Black"=>1, "Space"=>1, "Golden"=>1}
array_tally = array.tally

new_array = array.map.with_index do |value, index| 
    value_duplicated = array_tally[value] > 1
    
    if value_duplicated 
        "#{value} #{index}"
    else
       value 
    end
end

puts new_array.inspect
# output: ["Ballerina", "Lagoon 1", "Black", "Space", "Golden", "Lagoon 5"]
n9vozmp4

n9vozmp42#

输入

array = %w[Ballerina Lagoon Black Space Golden Lagoon]

编码

# create a hash of element counts

counts = array.each_with_object(Hash.new(0)) { |element, counts| counts[element] += 1 }
# iterate through array and append index to duplicates
array.each_with_index do |element, index|
  if counts[element] > 1
    array[index] = "#{element} #{index}"
  end
end

p array

输出

#=> ["Ballerina", "Lagoon 1", "Black", "Space", "Golden", "Lagoon 5"]
pdsfdshx

pdsfdshx3#

我会做:

arr = %w[Ballerina Lagoon Black Space Golden Lagoon]

cnt=arr.tally
arr2=arr.map.with_index{|e, i| cnt[e]>1 ? "#{e} #{i}" : e }

p arr2
# ["Ballerina", "Lagoon 1", "Black", "Space", "Golden", "Lagoon 5"]
ckx4rj1h

ckx4rj1h4#

这个答案适用于数组很大而重复数相对较少的情况,因为所建议的计算只需要通过数组一次。
请注意,我并不认为它一定比第一步使用Enumerable#tally方法的方法更快,只是它只需要一次遍历数组。
假设数组如下。

arr = ["Ballerina", "Space", "Lagoon", "Black", "Space", "Golden",
       "Lagoon", "Space"]

我们首先构造一个数组indices,它由arr的索引组成,对于indices的每个元素iarr[i]将以所需的方式进行修改。

indices = arr.each_with_index.
              with_object(Hash.new { |h,k| h[k] = [] }) do |(s,i),h|
                h[s] << i
              end.
              values.
              select { |a| a.size > 1 }.
              flatten
  #=> [1, 4, 7, 2, 6]

然后,我们根据需要通过迭代indices修改arr的副本。

indices.each_with_object(arr.dup) { |i,a| a[i] = "%s_%i" % [a[i], i] }
  #=> ["Ballerina", "Space_1", "Lagoon_2", "Black", "Space_4", "Golden",
  #    "Lagoon_6", "Space_7"]

通过检查Kernel#dup的源代码,人们发现-毫不奇怪-该方法(用C实现)复制了一个内存块,因此不构成arr元素的第二个枚举。
计算indices的步骤如下。

h = arr.each_with_index.
        with_object(Hash.new { |h,k| h[k] = [] }) do |(s,i),h|
          h[s] << i
        end
  #=> {"Ballerina"=>[0], "Space"=>[1, 4, 7], "Lagoon"=>[2, 6],
       "Black"=>[3], "Golden"=>[5]}
a = h.values
  #=> [[0], [1, 4, 7], [2, 6], [3], [5]]
b = a.select { |a| a.size > 1 }
  #=> [[1, 4, 7], [2, 6]]
b.flatten
  #=> [1, 4, 7, 2, 6]

相关问题