【问题标题】:Passing elements from one array to another, generating CSV将元素从一个数组传递到另一个数组,生成 CSV
【发布时间】:2018-11-22 04:25:24
【问题描述】:

我正在尝试用 Ruby 编写一个程序,该程序允许一个数组从另一个数组接收信息。基本上,我有一个名为“student_array”的多维数组,其中包含一些学生的信息

student_array = [["Mike", 13, "American", "male"], 
["Grace", 12, "Canadian", "female"],
["Joey", 13, "American", "male"],
["Lily", 13, "American", "female"]
]

我还初始化了另外两个将计算国籍的数组:

nationality_array = Array.new
nationality_count = Array.new

这个程序的目的是遍历学生数组,统计学生的不同国籍,并创建一个 CSV 文件,其中包含不同国籍的标题,以及每个民族的计数。

预期输出.csv

American, Canadian
3, 1

这是我目前的代码

student_array.each do |student|
    #pushes the nationality string into the nationality array
    nationality_array.push(student[2])   
end

因此,nationality_array 目前应该如下所示:

nationality_array = ["American", "Canadian", "American", "American"];
nationality_array.uniq = ["American", "Canadian"];

所以我将有两个标题 - “美国”和“加拿大”

现在我需要一种方法来遍历 student_array,计算“American”和“Canadian”的每个实例,并以某种方式将其分配回国籍数组。我很难想象如何去做。这就是我目前所拥有的——

american_count = 0;
canadian_count = 0;

student_array.each do |student|
    if student[2] = "American"
        american_count++
    elsif student[2] = "Canadian"
        canadian_count++
    end
end

nationality_count.push(american_count);
nationality_count.push(canadian_count);

好的,现在我在 nationality_count 数组中有这些计数,但是如何将其传递给 CSV,确保它们被分配给正确的标题?我觉得我的代码很笨拙,也可以更加精简。

它可能看起来像这样?

CSV.open("output/redemptions.csv", "wb") do |csv|
    csv << [nationality_array]
    csv << [nationality_count]
end

任何人都可以提供有关更清洁方法的任何见解吗?

【问题讨论】:

    标签: arrays ruby csv sorting each


    【解决方案1】:

    您可以使用Hash 按国籍而不是不同的数组对计数进行分组。

    nationalities_count = student_array.each_with_object(Hash.new(0)) do |student, hash| 
      nationality = student[2]
      hash[nationality] += 1
    end
    

    这会给你一个看起来像的哈希

    { "American" => 2, "Canadian" => 1 }
    

    然后您可以像这样使用Hash#to_aArray#transpose

    hsh = { "American" => 2, "Canadian" => 1 }
     => {"American"=>2, "Canadian"=>1}
    2.4.2 :002 > hsh.to_a
     => [["American", 2], ["Canadian", 1]]
    2.4.2 :003 > hsh.to_a.transpose
     => [["American", "Canadian"], [2, 1]]
    

    最后,要输出 CSV 文件,您只需将数组写入文件

    nationalities_with_count = hash.to_a.transpose
    CSV.open("output/redemptions.csv", "wb") do |csv|
      csv << nationalities_with_count[0]
      csv << nationalities_with_count[1]
    end
    

    【讨论】:

      【解决方案2】:

      Ruby 核心中的Array#group_by 和ActiveSupport 中的Hash#transform_values 是两种非常通用的方法,可以在这里使用:

      require 'active_support/all'
      require 'csv'
      
      student_array = [
        ["Mike", 13, "American", "male"], 
        ["Grace", 12, "Canadian", "female"],
        ["Joey", 13, "American", "male"],
        ["Lily", 13, "American", "female"]
      ]
      
      counts = student_array.group_by { |attrs| attrs[2] }.transform_values(&:length)
      # => => {"American"=>3, "Canadian"=>1}
      
      CSV.open("output/redemptions.csv", "wb") do |csv|
          csv << counts.keys
          csv << counts.values
      end
      
      puts File.read "output/redemptions.csv"
      # => American,Canadian
      #    3,1
      

      .group_by { |attrs| attrs[2] } 将数组转换为哈希,其中键是 attrs[2] 的唯一值,值是具有 attrs[2] 的元素列表。此时,您可以使用transform_values 将这些值转换为表示其长度的数字(意思是,有多少元素具有特定的attrs[2])。然后可以从哈希中提取键和值作为单独的数组。

      【讨论】:

        【解决方案3】:

        您甚至不需要 CSV 工具:

        result =
          student_array.
             map { |a| a[2] }.            # get nationalities
             group_by { |e| e }.          # hash
             map { |n, c| [n, c.count] }. # map values to count
             transpose.                   # put data in rows
             map { |row| row.join ',' }.  # join values in a row
             join($/)                     # join rows
        #⇒ American,Canadian
        #  3,1
        

        现在您有了一个有效的 CSV 字符串,只需将其吐出到文件中即可。

        【讨论】:

        • join($/) 在这里做什么?以前没见过这种用法。
        • @SRack 它是依赖于平台的行分隔符("\n" 在 unix 上,"\r\n" 在 Windows 上。)
        猜你喜欢
        • 1970-01-01
        • 2012-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多