从Ruby中的现有数组创建新数组

时间:2016-04-29 20:47:24

标签: ruby-on-rails arrays ruby ruby-on-rails-4

我有以下2个数组:

fields = ["name", "team", "number", "name", "team", "number", "name", "team", "number"]
values = ["Patrick Ewing", "New York Knicks", 33, "Rik Smits", "Indiana Pacers", 45, "Bill Russell", "Boston Celtics", 6]

字段将始终只是名称,团队和数字,但值的数量(即玩家数量)每次都会有所不同。

我想为每种字段类型创建新数组,以便我得到以下内容:

names = ["Patrick Ewing", "Rik Smits", "Bill Russell"]
teams = ["New York Knicks", "Indiana Pacers", "Boston Celtics"]
numbers = [33,45,6]

这样做的好方法是什么?我尝试了以下内容,但想知道是否有其他解决方案可以更好地使用更大的阵列(最多300个)。或者差异可以忽略不计?

names = values.values_at(*(fields.each_index.select{ |i| fields[i] == "name"}))
teams = values.values_at(*(fields.each_index.select{ |i| fields[i] == "team"}))
numbers = values.values_at(*(fields.each_index.select{ |i| fields[i] == "number"}))

5 个答案:

答案 0 :(得分:5)

这是另一种/简洁的方式:

> name, team, number = values.each_slice(3).to_a.transpose
=> name
> ["Patrick Ewing", "Rik Smits", "Bill Russell"]
=> team
> ["New York Knicks", "Indiana Pacers", "Boston Celtics"]
=> number
> [33, 45, 6]

Ruby Array#transpose的美丽发挥作用,尤其适用于您的问题。

答案 1 :(得分:3)

您可以在一行中使用group_bywith_index

grouped = values.group_by.with_index {|_, i| fields[i] }
#=> {"name"=>["Patrick Ewing", "Rik Smits", "Bill Russell"],'
    "team"=>["New York Knicks", "Indiana Pacers", "Boston Celtics"],            
    "number"=>[33, 45, 6]}

然后,您可以从此哈希中简单地生成数组:

name = grouped["name"]
#=> ["Patrick Ewing", "Rik Smits", "Bill Russell"]

或者只是:

names, teams, numbers = grouped.values

答案 2 :(得分:2)

如果输入始终为三个一组,则可以使用each_slice

values = ["Patrick Ewing", "New York Knicks", 33, "Rik Smits", "Indiana Pacers", 45, "Bill Russell", "Boston Celtics", 6]

names = [ ]
teams = [ ]
numbers = [ ]

values.each_slice(3) do |name, team, number|
  names << name
  teams << team
  numbers << number
end

这不是组织事物的最佳方式。更加面向Ruby的风格是:

keys = [ :name, :team, :number ]

players = values.each_slice(3).collect do |set|
  Hash[keys.zip(set)]
end
#=> [{:name=>"Patrick Ewing", :team=>"New York Knicks", :number=>33}, {:name=>"Rik Smits", :team=>"Indiana Pacers", :number=>45}, {:name=>"Bill Russell", :team=>"Boston Celtics", :number=>6}]

这使您可以轻松访问每条记录,而无需交叉引用多个数组。即使您在表格中显示此内容并且需要单独使用这三项内容,您仍然可以选择输出单个值:

keys.each do |key|
  players.each do |player|
    print '%-20s' % player[key]
  end

  puts
end

这会给你输出:

Patrick Ewing       Rik Smits           Bill Russell        
New York Knicks     Indiana Pacers      Boston Celtics      
33                  45                  6                   

答案 3 :(得分:1)

以下是通过“type”对数组值进行分组的一种方法:

fields = ["name", "team", "number", "name", "team", "number", "name", "team", "number"]
values = ["Patrick Ewing", "New York Knicks", 33, "Rik Smits", "Indiana Pacers", 45, "Bill Russell", "Boston Celtics", 6]

field_values = fields.zip(values)

names = field_values.select { |f, v| f == "name" }.map(&:last)
# => ["Patrick Ewing", "Rik Smits", "Bill Russell"]

teams = field_values.select { |f, v| f == "team" }.map(&:last)
# => ["New York Knicks", "Indiana Pacers", "Boston Celtics"]

numbers = field_values.select { |f, v| f == "number" }.map(&:last)
# => [33, 45, 6]

答案 4 :(得分:1)

另一种方式:使用Facets Enumerable#map_by

require 'facets'
names, teams, numbers = fields.zip(values).
  map_by { |field, value| [field, value] }.
  values_at("name", "team", "number")