1

私は Ruby を学ぼうとしている Perl 開発者です... そこで、私が Ruby で達成しようとしていることを Perl でデモンストレーションし、最後に要約します...

#!/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 で使用したのと同じコード構造に似た map でのいくつかの試行を含め、これを複数回試みましたが、役に立ちませんでした。

そうは言っても、今、次のスニペットを見つけましたが、これはほとんど機能しますが、何か間違っていると確信しています...

h = Hash[j.collect {|array| [array.key1,array.key4] }]

これで正しいハッシュ キーが得られますが、key4 の値がハッシュの配列にプッシュされません。まだ探していますが、正しい方向への微調整をいただければ幸いです。ここで答えを得る前に答えを見つけた場合は、将来の読者の教育のために質問に答えます.

編集!私はちょうど私が理解した何かを明確にする必要があり、おそらく私の時計のレンチです. 取得しているデータは純粋な配列ではありません。実際には DataMapper のオブジェクトです。

4

4 に答える 4

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"]}
于 2013-03-06T22:26:14.240 に答える
2

「与えられた次のデータ構造 (ハッシュの配列)」から始めたとき、あなたはすでに Perl で考えていました。慣用的な Ruby では、オブジェクトの配列になります。実際、これはデータベース呼び出しなどの出力の典型です。サンプルクラス:

class Item
  attr_accessor :id, :name, :data, :foo
end

そのようなアイテムの配列がある場合、答えは次のようになります。

items.group_by(&:name)

もちろん、これははるかにクリーンで表現力豊かです。

上記では、求めている正確なデータ構造が得られないことに注意してください。データ構造をばらまくのはアンチパターンです。あなたが求めている出力は、確かに他の何かに完全に使用される中間構造です(ビューで出力を印刷する、ストレージのためにシリアル化するなど)。したがって、私はそれが必要ではないと主張します。グループ化されたオブジェクトのリストを使用して、必要なことを行うことができます。

于 2013-03-06T22:46:03.037 に答える
0

別の方法:

Hash[j.chunk {|e| e['key1'] }.map {|k, ary| [k, ary.map {|x| x['key4'] }] }]
=> {"name1"=>["foo", "bar"], "name2"=>["baz"]}

しかし、これまでのところdbenhurの答えが一番好きだと思います。

于 2013-03-06T22:39:00.503 に答える
0

ここにワンライナーがあります。「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 にあります。

于 2013-03-06T22:31:59.457 に答える