从数组中创建一个哈希值,其中值是元素的索引

时间:2018-05-28 19:01:14

标签: ruby

我有一个数组,我想创建一个哈希,其键是数组的元素,其值是(数组)数组的索引。我希望得到类似的东西:

array = [1,3,4,5]
... # => {1=>0, 3=>1, 4=>2, 5=>3}

array = [1,3,4,5,6,6,6]
... # => {1=>0, 3=>1, 4=>2, 5=>3, 6=>[4,5,6]}

此代码:

hash = Hash.new 0
array.each_with_index do |x, y|
  hash[x] = y
end

只有在我没有重复元素的情况下才能正常工作。当我有重复的元素时,它不会。

我对如何得到这样的东西有任何想法吗?

3 个答案:

答案 0 :(得分:3)

您可以将逻辑更改为特殊情况,当密钥已存在时,将其转换为数组并推送新索引:

arr = %i{a a b a c}

result = arr.each.with_object({}).with_index do |(elem, memo), idx|
  memo[elem] = memo.key?(elem) ? [*memo[elem], idx] : idx
end

puts result
# => {:a=>[0, 1, 3], :b=>2, :c=>4}
不过,值得一提的是,无论你在这里做什么,都可能以不同的方式完成......我们没有背景。一般来说,保持key-val数据类型一致是一个好主意,例如这里的值可以是数字或数组的事实是一些代码味道。

另请注意,在此处使用Hash.new(0)是没有意义的,除非您有意设置默认值(没有理由这样做)。请改用{}

答案 1 :(得分:2)

我加了两分钱:

array = [1,3,4,5,6,6,6,8,8,8,9,7,7,7]

hash = {}
array.map.with_index {|val, idx| [val, idx]}.group_by(&:first).map do |k, v|
  hash[k] = v[0][1] if v.size == 1
  hash[k] = v.map(&:last) if v.size > 1
end

p hash #=> {1=>0, 3=>1, 4=>2, 5=>3, 6=>[4, 5, 6], 8=>[7, 8, 9], 9=>10, 7=>[11, 12, 13]}

当然,它失败了,重复元素不相邻。

这是一步一步的扩展版本,以展示它的工作原理。

基本思想是构建一个具有值和索引对的临时数组,然后对其进行处理。

array = [1,3,4,5,6,6,6]

tmp_array = []
array.each_with_index do |val, idx|
  tmp_array << [val, idx]
end
p tmp_array #=> [[1, 0], [3, 1], [4, 2], [5, 3], [6, 4], [6, 5], [6, 6]]

tmp_hash = tmp_array.group_by { |e| e[0] }
p tmp_hash #=> {1=>[[1, 0]], 3=>[[3, 1]], 4=>[[4, 2]], 5=>[[5, 3]], 6=>[[6, 4], [6, 5], [6, 6]]}

hash = {}
tmp_hash.map do |k, v|
  hash[k] = v[0][0] if v.size == 1
  hash[k] = v.map {|e| e[1]} if v.size > 1
end

p hash #=> {1=>1, 3=>3, 4=>4, 5=>5, 6=>[4, 5, 6]}

它可以写成一行:

hash = {}
array.map.with_index.group_by(&:first).map { |k, v| v.size == 1 ? hash[k] = v[0][1] : hash[k] = v.map(&:last) }
p hash

答案 2 :(得分:2)

如果您准备接受

@a = sort { $a <=> $b } @a

作为返回值,您可以写下以下内容。

{ 1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4,5,6] }

此计算的第一步如下。

array.each_with_index.group_by(&:first).transform_values { |v| v.map(&:last) }
  #=> {1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4, 5, 6]}

这可以帮助读者遵循后续计算。

我认为你会发现这个返回值通常比问题中给出的更方便。

以下是几个例子,它们显然更适合所有值为数组。让:

array.each_with_index.group_by(&:first)
  #=> {1=>[[1, 0]], 3=>[[3, 1]], 4=>[[4, 2]], 5=>[[5, 3]], 6=>[[6, 4], [6, 5], [6, 6]]}

创建一个哈希h_orig = { 1=>0, 3=>1, 4=>2, 5=>3, 6=>[4,5,6] } h_mod { 1=>[0], 3=>[1], 4=>[2], 5=>[3], 6=>[4,5,6] } ,其键是h的唯一元素,其值是键在数组中出现的次数

array

创建一个哈希h_mod.transform_values(&:count) #=> {1=>1, 3=>1, 4=>1, 5=>1, 6=>3} h_orig.transform_values { |v| v.is_a?(Array) ? v.count : 1 } ,其键是h的唯一元素,其值等于数组中第一个元素实例的索引。

array

在这些示例中,给定h_mod.transform_values(&:min) #=> {1=>0, 3=>1, 4=>2, 5=>3, 6=>4} h_orig.transform_values { |v| v.is_a?(Array) ? v.min : v } ,我们可以将索引值转换为包含单个索引的数组。

h_orig

这几乎不能证明所有值都是数组通常更方便,但这是我的经验和许多其他人的经验。