【问题标题】:How to make Ruby hash of arrays from array如何从数组制作数组的Ruby散列
【发布时间】:2013-03-06 22:00:09
【问题描述】:

我是一名尝试学习 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 中使用的相同代码结构的 map 均无济于事。

也就是说,我确实找到了以下 sn-p,刚才,它几乎可以工作,但我确定我做错了什么......

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

这为我提供了正确的哈希键,但它不会将 key4 值推送到哈希数组中。仍在寻找,但在正确的方向上轻推一些将不胜感激。如果我在这里得到答案之前找到答案,我会回答这个问题,以启发未来的读者。

编辑! 我需要澄清一些我刚刚发现的东西,可能是我时钟上的扳手。我得到的数据不是纯数组。它实际上是来自 DataMapper 的一个对象。

【问题讨论】:

  • 它可能与 Perl 风格的传统背道而驰,但您可能更喜欢清晰而不是简洁 - 仅仅因为您 可以 使其成为单行,并不意味着您应该。您确实想要的是能够在 6 个月内回到它,而不是想“到底是谁写了这个想法?”
  • 在 Ruby 中,您可以通过正确分解的代码获得清晰的简洁性。

标签: ruby multidimensional-array hashmap ruby-datamapper


【解决方案1】:

您正在执行分组操作。 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"]}

【讨论】:

    【解决方案2】:

    当您从“给定以下数据结构(哈希数组)”开始时,您已经在考虑 Perl。在惯用的 Ruby 中,它将是一个对象数组。事实上,这是数据库调用等的典型输出。示例类:

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

    如果您有一系列此类项目,您的答案可能如下所示:

    items.group_by(&:name)
    

    当然更干净,更有表现力。

    请注意,以上内容并未提供您所要求的确切数据结构。到处乱扔数据结构是一种反模式。您要求的输出肯定是一个中间结构,将完全用于其他用途(在视图中打印输出;序列化以进行存储等)。因此,我认为没有必要。您可以使用分组的对象列表来做您需要的事情。

    【讨论】:

    • 啊,这很有趣,我肯定在考虑 Perl 与 Ruby,所以这似乎是朝着正确方向的一个很好的推动......
    • @Jim 我自己来自 Perl 背景。在 Perl 中,数据结构比 OO 更容易。在 Ruby 中,情况正好相反。
    • 即使将元素建模为对象,您的答案也无法达到 OP 的预期结果,即来自 :name => [set of :data] 的映射。 items.group_by(&:name).each_with_object({}) {|(k,v),m| m[k] = v.map(&:data) } 一路走来。
    • 我的意思是,您不必考虑数据结构,无论是作为输入还是作为输出。我没有给他他想要的结果,因为我是在要求他重​​新考虑他想要的结果。 :)
    • 如果我有像大多数这些答案一样的代码,我会重构。正在完成的工作类型过于复杂。
    【解决方案3】:

    这是一个单行线。假设 '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 中。

    【讨论】:

      【解决方案4】:

      另一种方式:

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

      但我认为我最喜欢 dbenhur 的回答。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-01
        • 2014-08-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-24
        相关资源
        最近更新 更多