如何用相同的元素对数组进行分组?

时间:2015-11-25 10:35:33

标签: arrays ruby

我有一个包含以下元素的数组:

array = [1, 2, 1, 3, 2, nil, 3, 3]

我想通过匹配元素对它们进行分组并将其分配给哈希。输出应该如下所示:

{ one: [1, 1], two: [2, 2], three: [3, 3, 3], none: [nil] }

注意:array只能包含123nil元素。

密钥(:one:two:three:none)可以进行硬编码。

4 个答案:

答案 0 :(得分:6)

group_by可以itself数组(元素):

array = [1, 2, 1, 3, 2, nil, 3, 3]
hash = array.group_by(&:itself)
#=> {1=>[1, 1], 2=>[2, 2], 3=>[3, 3, 3], nil=>[nil]}

之后,您可以使用map来重命名"钥匙:

keys = { 1 => :one, 2 => :two, 3 => :three, nil => :none }
hash.map { |k, v| [keys[k], v] }.to_h
#=> {:one=>[1, 1], :two=>[2, 2], :three=>[3, 3, 3], :none=>[nil]}

答案 1 :(得分:1)

来自Perl背景,我曾经习惯于模糊阵列和哈希的混淆方法。以下是它如何损害我:

使用window.location是找到相似之处的明显方法:

group_by

使用哈希是从一件事物到另一件事物的简单方法:

array = [1, 2, 1, 3, 2, nil, 3, 3]
hash = array.group_by{ |i| i } # => {1=>[1, 1], 2=>[2, 2], 3=>[3, 3, 3], nil=>[nil]}

Perl影响力影响了我的想法:

new_keys = {
  1   => :one,
  2   => :two,
  3   => :three,
  nil => :none
}

因为他们都做同样的事情,但以不同的方式,我想知道什么是最快的。而且,因为我喜欢@ Stefan的new_keys.values.zip(hash.values_at(*new_keys.keys)).to_h # => {:one=>[1, 1], :two=>[2, 2], :three=>[3, 3, 3], :none=>[nil]} new_keys.each_with_object({}){ |(k, v), h| h[v] = hash[k] } # => {:one=>[1, 1], :two=>[2, 2], :three=>[3, 3, 3], :none=>[nil]} new_keys.inject({}){ |h, (k, v)| h[v] = hash[k]; h } # => {:one=>[1, 1], :two=>[2, 2], :three=>[3, 3, 3], :none=>[nil]} 方法,所以我想看看特定方法是否有任何速度优势:

map

Fruity无法找到任何显着的速度差异,而后台任务正在影响找到一致差异的能力,所以我进行了五次比较。根据结果​​的顺序暗示​​了微小的差异,但这些看起来都是一个很好的方法:

require 'fruity'

5.times do

  compare do
    _zip              { new_keys.values.zip(hash.values_at(*new_keys.keys)).to_h    }
    _each_with_object { new_keys.each_with_object({}){ |(k, v), h| h[v] = hash[k] } }
    _inject           { new_keys.inject({}){ |h, (k, v)| h[v] = hash[k]; h }        }
    _map              { hash.map { |k, v| [new_keys[k], v] }.to_h                   }
  end

  puts
end

答案 2 :(得分:1)

使用humanize gem将数字转换为单词的简短解决方案。

require 'humanize'
array.group_by { |e| e.humanize.to_sym rescue :none }
# => {:one=>[1, 1], :two=>[2, 2], :three=>[3, 3, 3], :none=>[nil]}

答案 3 :(得分:0)

这个怎么样

hash = array.group_by{|e| e}

[hash].each do |k|
   k[:one] = k.delete 1
   k[:two] = k.delete 2
   k[:three] = k.delete 3
   k[:none] = k.delete nil
end

你会得到你的输出。如果您不想循环执行以下操作

hash[:one] = hash.delete 1
hash[:two] = hash.delete 2
hash[:three] = hash.delete 3
hash[:none] = hash.delete nil