Arrays 如何在Ruby中将数组转换为另一个数组

Arrays 如何在Ruby中将数组转换为另一个数组,arrays,ruby,csv,Arrays,Ruby,Csv,我有这样一个多维数组: myArray = [["Alaska","Rain","3"],["Alaska","Snow","4"],["Alabama","Snow","2"],["Alabama","Hail","1"]] 我想以这样的CSV输出结束 State,Snow,Rain,Hail Alaska,4,3,nil Alabama,2,nil,1 我知道要以我想要的方式将其输出到CSV,我必须有如下输出数组: outputArray =[["State","Snow","Rain"

我有这样一个多维数组:

myArray = [["Alaska","Rain","3"],["Alaska","Snow","4"],["Alabama","Snow","2"],["Alabama","Hail","1"]]
我想以这样的CSV输出结束

State,Snow,Rain,Hail
Alaska,4,3,nil
Alabama,2,nil,1
我知道要以我想要的方式将其输出到CSV,我必须有如下输出数组:

outputArray =[["State","Snow","Rain","Hail"],["Alaska",4,3,nil],["Alabama",2,nil,1]]
但我不知道如何进入这个阶段。
我尝试过使用group_by,但没有成功。

我认为您可能需要为此行为创建一个自定义的
类,以便将整个功能包装到一个对象中

该类将接受输入数组的一个实例,并将返回已转换的输出,以便进行序列化

您需要的是:

  • 包含标头列表的数组,在循环输入项时动态填充
  • 一种散列,其中键是状态,值是头/值的散列

    { "Alabama" => { "Snow" => 2 }}
    
  • 初始化对象时,
    @headers
    是空数组,
    @data
    是空哈希

    您循环输入数组中的所有项目,对于列表中的每个项目,如果尚未添加到
    @headers
    (事实上,您可以使用
    集合
    ,而不是
    数组
    ,它将为您删除重复项),然后将项目添加到
    @数据

    如果国家/地区中已存在该状态,请添加新的键/值。如果状态不存在,则创建状态并添加新的键/值。您可以通过一行代码轻松实现此目标

    # assuming `state` is the current state in the loop
    (@data[state] ||= {}).merge(header => value)
    
    循环结束时,
    @header
    将包含要显示的所有项目。此时,循环
    @data
    并为每个项目提取
    @header
    中声明的所有值。如果该值不存在,请使用nil


    在第二个循环结束时,您将获得生成CSV所需的数据。

    我认为您可能需要为此行为创建一个自定义的
    ,以便将整个功能包装到一个对象中

    该类将接受输入数组的一个实例,并将返回已转换的输出,以便进行序列化

    您需要的是:

  • 包含标头列表的数组,在循环输入项时动态填充
  • 一种散列,其中键是状态,值是头/值的散列

    { "Alabama" => { "Snow" => 2 }}
    
  • 初始化对象时,
    @headers
    是空数组,
    @data
    是空哈希

    您循环输入数组中的所有项目,对于列表中的每个项目,如果尚未添加到
    @headers
    (事实上,您可以使用
    集合
    ,而不是
    数组
    ,它将为您删除重复项),然后将项目添加到
    @数据

    如果国家/地区中已存在该状态,请添加新的键/值。如果状态不存在,则创建状态并添加新的键/值。您可以通过一行代码轻松实现此目标

    # assuming `state` is the current state in the loop
    (@data[state] ||= {}).merge(header => value)
    
    循环结束时,
    @header
    将包含要显示的所有项目。此时,循环
    @data
    ,并为每个项目提取
    @header
    中声明的所有值。如果该值不存在,请使用nil


    在第二个循环结束时,您将获得生成CSV所需的数据。

    这里有一种使用散列的中间散列的方法

    h
    最后看起来像这样

    {"Alaska"=>{"Rain"=>"3", "Snow"=>"4"}, "Alabama"=>{"Snow"=>"2", "Hail"=>"1"}}
    


    输出

    [["State", "Snow", "Rain", "Hail"], ["Alaska", "4", "3", nil], ["Alabama", "2", nil, "1"]]
    

    下面是一种使用散列的中间散列的方法

    h
    最后看起来像这样

    {"Alaska"=>{"Rain"=>"3", "Snow"=>"4"}, "Alabama"=>{"Snow"=>"2", "Hail"=>"1"}}
    


    输出

    [["State", "Snow", "Rain", "Hail"], ["Alaska", "4", "3", nil], ["Alabama", "2", nil, "1"]]
    

    我建议你按如下方式做:

    my_array = [["Alaska" ,"Rain","3"], ["Alaska", "Snow","4"],
                ["Alabama","Snow","2"], ["Alabama","Hail","1"]]
    
    attributes = my_array.transpose[1].uniq
      #=> ["Rain", "Snow", "Hail"]
    
    h = my_array.each_with_object({}) { |a,h| (h[a.first] ||= {})[a[1]] = a[2].to_i }
      #=> {"Alaska" =>{"Rain"=>3, "Snow"=>4},
      #    "Alabama"=>{"Snow"=>2, "Hail"=>1}} 
    
    [["State", *attributes], *h.map { |k,v| [k, *v.values_at(*attributes)] }]
      #=> [["State", "Rain", "Snow", "Hail"],
      #    ["Alaska",    3, 4, nil],
      #    ["Alabama", nil, 2,   1]] 
    
    当然,您可以替换掉
    h

    让我们更仔细地看一下以下各项的计算:

    h.map { |k,v| [k, *v.values_at(*attributes)] }]
    
    我们有:

    enum = h.map
      #=> #<Enumerator: {"Alaska"=>{"Rain"=>3,  "Snow"=>4},
      #                  "Alabama"=>{"Snow"=>2, "Hail"=>1}}:map> 
    
    enum
    的第二个元素被传递到块中:

    k,v = enum.next
      #=> ["Alabama", {"Snow"=>2, "Hail"=>1}] 
    b = v.values_at(*attributes)
      #=> [nil, 2, 1] 
    [k, *b]
      #=> ["Alabama", nil, 2, 1] 
    

    我建议你按如下方式做:

    my_array = [["Alaska" ,"Rain","3"], ["Alaska", "Snow","4"],
                ["Alabama","Snow","2"], ["Alabama","Hail","1"]]
    
    attributes = my_array.transpose[1].uniq
      #=> ["Rain", "Snow", "Hail"]
    
    h = my_array.each_with_object({}) { |a,h| (h[a.first] ||= {})[a[1]] = a[2].to_i }
      #=> {"Alaska" =>{"Rain"=>3, "Snow"=>4},
      #    "Alabama"=>{"Snow"=>2, "Hail"=>1}} 
    
    [["State", *attributes], *h.map { |k,v| [k, *v.values_at(*attributes)] }]
      #=> [["State", "Rain", "Snow", "Hail"],
      #    ["Alaska",    3, 4, nil],
      #    ["Alabama", nil, 2,   1]] 
    
    当然,您可以替换掉
    h

    让我们更仔细地看一下以下各项的计算:

    h.map { |k,v| [k, *v.values_at(*attributes)] }]
    
    我们有:

    enum = h.map
      #=> #<Enumerator: {"Alaska"=>{"Rain"=>3,  "Snow"=>4},
      #                  "Alabama"=>{"Snow"=>2, "Hail"=>1}}:map> 
    
    enum
    的第二个元素被传递到块中:

    k,v = enum.next
      #=> ["Alabama", {"Snow"=>2, "Hail"=>1}] 
    b = v.values_at(*attributes)
      #=> [nil, 2, 1] 
    [k, *b]
      #=> ["Alabama", nil, 2, 1] 
    

    此问题需要更多@sawa。此问题需要更多@sawa。详细信息:OP希望将表示整数的字符串转换为整数。@CarySwoveland,当写入CSV文件时没有任何区别
    h[i][j]=k.to_i
    可以在需要时执行。详细信息:OP希望表示整数的字符串转换为整数。@CarySwoveland,在写入CSV文件时没有任何区别
    h[i][j]=k.to\u如果需要的话我会做的。我用你的
    v.values\u在(*属性)
    来改进我的答案:)我用你的
    v.values\u在(*属性)
    来改进我的答案:)