奇怪的Ruby group_by和选择行为

时间:2022-06-29 10:17:19

I'm getting strange behavior when trying to select from a hash created with group_by:

尝试从使用group_by创建的哈希中进行选择时,我会遇到奇怪的行为:

When I run

当我跑

all_records.group_by(&:opportunity).map{|foo| foo[1].length != 1 }.select{|x| x}

I get some elements back: => [true, true]

我得到了一些元素:=> [true,true]

Yet when I try and select, with the exact block I mapped:

然而,当我尝试选择时,使用我映射的确切块:

all_records.group_by(&:opportunity).select{|foo| foo[1].length != 1 }

I get no results: => {}

我没有得到任何结果:=> {}

Just as a sanity check, it works as expected when i first convert the hash to an array with sort:

正如一个完整性检查,当我第一次将哈希转换为具有排序的数组时,它按预期工作:

all_records.group_by(&:opportunity).sort.select{|foo| foo[1].length != 1 }.length

Result: => 2

结果:=> 2

It's strange to me, because the first result indicates that the hash recognized the foo[1] command perfectly. What's causing this?

这对我来说很奇怪,因为第一个结果表明哈希完全识别了foo [1]命令。是什么导致了这个?

1 个解决方案

#1


2  

In the first snippet you are doing a Enumerable#map on a hash, with a block that gets a single argument (why don't you unpack it?), and here you get a pair (as you expected). In the second snippet you are doing a Hash#select again with a single argument (and again you should unpack the key/value), but here you get only the key, not the pair (because of how the method is implemented, check the source code for details).

在第一个片段中,你在一个哈希上做一个Enumerable #map,一个块得到一个参数(为什么你不解压缩?),在这里你得到一对(如你所料)。在第二个片段中,您正在使用单个参数再次执行Hash #select(并且您应该再次解压缩键/值),但是这里只获取键,而不是对(因为方法的实现方式,请检查源代码详情)。

>> {a: 1, b: 2}.map { |x| p x }
[:a, 1]
[:b, 2]
>> {a: 1, b: 2}.select { |x| p x }
:a
:b

If you go to the docs for Hash#select, you'll see it explicitly requires unpacked arguments. Conclusion: always unpack the key/value when iterating hashes with any method:

如果你转到Hash #select的文档,你会发现它显然需要解压缩的参数。结论:在使用任何方法迭代哈希时,始终解压缩键/值:

records.group_by(&:opportunity).select { |key, values| values.length > 1 }

#1


2  

In the first snippet you are doing a Enumerable#map on a hash, with a block that gets a single argument (why don't you unpack it?), and here you get a pair (as you expected). In the second snippet you are doing a Hash#select again with a single argument (and again you should unpack the key/value), but here you get only the key, not the pair (because of how the method is implemented, check the source code for details).

在第一个片段中,你在一个哈希上做一个Enumerable #map,一个块得到一个参数(为什么你不解压缩?),在这里你得到一对(如你所料)。在第二个片段中,您正在使用单个参数再次执行Hash #select(并且您应该再次解压缩键/值),但是这里只获取键,而不是对(因为方法的实现方式,请检查源代码详情)。

>> {a: 1, b: 2}.map { |x| p x }
[:a, 1]
[:b, 2]
>> {a: 1, b: 2}.select { |x| p x }
:a
:b

If you go to the docs for Hash#select, you'll see it explicitly requires unpacked arguments. Conclusion: always unpack the key/value when iterating hashes with any method:

如果你转到Hash #select的文档,你会发现它显然需要解压缩的参数。结论:在使用任何方法迭代哈希时,始终解压缩键/值:

records.group_by(&:opportunity).select { |key, values| values.length > 1 }