1

我有一个数组,我想将其转换为由项目键入的哈希映射,并将索引数组作为值。例如

arr = ["a", "b", "c", "a"] 

会成为

hsh = {"a": [0,3], "b": [1], "c": [2]}

我想以一种功能性的方式(而不是一个大的旧 for 循环)来做到这一点,但我有点卡住了

lst = arr.collect.with_index { |item, i| [item, i] }

生产

[["a", 0], ["b", 1], ["c", 2], ["a", 3]]

然后我尝试了 Hash[lst],但我没有得到值中的数组并丢失索引 0

{"a"=>3, "b"=>1, "c"=>2}

如何以实用的方式获得所需的输出?我觉得有点像

Hash[arr.collect.with_index { |item, i| [item, item[i] << i || [i] }]

但这不会产生任何结果。

注意:尽量要这样做

hsh = {}
arr.each.with_index do |item, index|
   if hsh.has_key?(item)
      hsh[item] << index
   else 
      hsh[item] = [index]
   end 
end
hsh
4

3 回答 3

3

输入

arr = ["a", "b", "c", "a"]

代码

p arr.map
      .with_index
      .group_by(&:first)
      .transform_values { |arr| arr.map(&:last) }

输出

{"a"=>[0, 3], "b"=>[1], "c"=>[2]}
于 2020-10-24T13:16:59.957 回答
2

我想以一种功能性的方式(而不是一个大的旧 for 循环)来做到这一点,但我有点卡住了

lst = arr.collect.with_index { |item, i| [item, i] }

生产

[["a", 0], ["b", 1], ["c", 2], ["a", 3]]

这非常接近。我要做的第一件事是将内部数组更改为哈希:

arr.collect.with_index { |item, i| { item => i }}
#=> [{ "a" => 0 }, { "b" => 1 }, { "c" => 2 }, { "a" => 3 }]

这又近了一步。现在,实际上我们想要数组中的索引:

arr.collect.with_index { |item, i| { item => [i] }}
#=> [{ "a" => [0] }, { "b" => [1] }, { "c" => [2] }, { "a" => [3] }]

这更接近了。现在,我们需要做的就是将这些散列合并为一个散列。有一种方法,称为Hash#merge. 它需要一个可选块来消除重复键的冲突,我们需要做的就是连接数组:

arr.collect.with_index { |item, i| { item => [i] }}.inject({}) {|acc, h| acc.merge(h) {|_, a, b| a + b } }
#=> { "a" => [0, 3], "b" => [1], "c" => [2] }

我们完成了!

如何以实用的方式获得所需的输出?我觉得有点像

Hash[arr.collect.with_index { |item, i| [item, item[i] << i || [i] }]

但这不会产生任何结果。

好吧,它有一个SyntaxError,所以很明显,如果它甚至不能被解析,那么它就不能运行,如果它甚至不运行,那么它就不可能产生任何东西。

但是,即使起作用了,它仍然会违反您应该“以功能方式”完成的约束,因为Array#<<它的接收器会发生变异,因此不起作用。

于 2020-10-24T13:20:44.960 回答
0
 arr.map.with_index.each_with_object({}){ |(a, i), h| h[a] ? h[a] << i : (h[a] = [i]) }
 #=> {"a"=>[0, 3], "b"=>[1], "c"=>[2]}

arr.map.with_index=> 用它的索引枚举每个元素

each_with_object=> 让您减少对提供的对象的枚举(由h上面表示)

于 2020-10-24T12:55:45.560 回答