我是一名试图学习Ruby的Perl开发人员... 所以,我将在Perl中演示我在Ruby中想要实现的内容,然后在最后总结...
#!/usr/bin/perl -w
use strict;
use Data::Dumper;
# Given the following data structure (an array of hashes)
my $j = [
{
id => 1,
key1 => 'name1',
key2 => 'data',
key3 => 'data',
key4 => 'foo',
},
{
id => 2,
key1 => 'name1',
key2 => 'data',
key3 => 'data',
key4 => 'bar',
},
{
id => 3,
key1 => 'name2',
key2 => 'data',
key3 => 'data',
key4 => 'baz',
},
];
print ~~@$j,"\n";
print Dumper($j)."\n";
my $myHash; # make it a reference to a hoa.
for my $array ( @{$j} )
{
# the key to my new key-name is always known
push(@{$myHash->{$array->{key1}}},$array->{key4});
}
print Dumper($myHash)."\n";
输出:
初始数组:
$VAR1 = [
{
'key2' => 'data',
'key4' => 'foo',
'key1' => 'name1',
'id' => 1,
'key3' => 'data'
},
{
'key2' => 'data',
'key4' => 'bar',
'key1' => 'name1',
'id' => 2,
'key3' => 'data'
},
{
'key2' => 'data',
'key4' => 'baz',
'key1' => 'name2',
'id' => 3,
'key3' => 'data'
}
];
我想要的是:
$VAR1 = {
'name2' => [
'baz'
],
'name1' => [
'foo',
'bar'
]
};
...而且我正在尝试尽可能简洁的代码,鉴于我缺乏Ruby的优点,这已被证明是一种痛苦。我已尝试多次尝试,包括在地图上进行多次尝试,类似于我在Perl中使用的相同代码结构,但无效。
那就是说,我确实找到了以下片段,这几乎是有效的,但我确定我做错了......
h = Hash[j.collect {|array| [array.key1,array.key4] }]
这为我提供了正确的哈希键,但它没有将key4值推送到哈希数组中。仍然看起来,但正确的方向一些推动将不胜感激。如果我在得到答案之前找到答案,我会回答未来读者的启发问题。
EDIT! 我需要澄清一些我刚才想到的东西,可能是我时钟的扳手。我得到的数据不是纯数组。它实际上是DataMapper中的一个对象。
答案 0 :(得分:4)
您正在按操作执行分组。 Enumerable#group_by
生成一个哈希,其键是块中的值,其值是具有该键的所有初始元素的数组。
然后,您可以使用Enumerable#each_with_object
创建包含这些键的新哈希值,但这些值会减少为您想要的key4元素。
a = [
{ id: 1, key1: 'name1', key2: 'data', key3: 'data', key4: 'foo', },
{ id: 2, key1: 'name1', key2: 'data', key3: 'data', key4: 'bar', },
{ id: 3, key1: 'name2', key2: 'data', key3: 'data', key4: 'baz', },
]
res = a.group_by { |e| e[:key1] }.
each_with_object({}) { |(k,v),m| m[k] = v.map{|e| e[:key4]} }
puts res.inspect
# => {"name1"=>["foo", "bar"], "name2"=>["baz"]}
答案 1 :(得分:2)
当您开始使用“给定以下数据结构(散列数组)”时,您已经在考虑使用Perl。在惯用的Ruby中,它将是一个对象数组。实际上,这是典型的数据库调用输出等。示例类:
class Item
attr_accessor :id, :name, :data, :foo
end
如果您有一系列此类项目,您的答案可能如下所示:
items.group_by(&:name)
当然更清洁,更具表现力。
请注意,上述内容并未提供您要求的确切数据结构。抛弃数据结构是一种反模式。您要求的输出肯定是一个中间结构,将完全用于其他东西(在视图中打印输出;用于存储的序列化等)。因此,我认为没有必要。您可以使用分组的对象列表来执行所需的操作。
答案 2 :(得分:0)
这是一个oneliner。假设'ar'绑定到您的数组。分配r = {}然后:
ar.map { |a| { a[:key1] => a[:key4] }}.each { |m| m.each { |key,val| r[key] = if not r[key] then [val] else r[key].push(val) end }
结果在r。
答案 3 :(得分:0)
另一种方式:
Hash[j.chunk {|e| e['key1'] }.map {|k, ary| [k, ary.map {|x| x['key4'] }] }]
=> {"name1"=>["foo", "bar"], "name2"=>["baz"]}
但我认为到目前为止我最喜欢dbenhur的答案。