【问题标题】:Fetch the data from the CSV files in ruby and Order the Data in DESC?从 ruby​​ 中的 CSV 文件中获取数据并在 DESC 中排序数据?
【发布时间】:2021-07-16 18:46:55
【问题描述】:

这是我的 CSV 文件值

Name , Sales
Randy, 200
Robin, 502
Randy, 200
Raj,   502
Randy, 500      
Robin, 102      
Mano,  220
Raj,   502
Randy, 285
Robin, 385
Randy, 295
Raj,   596

我需要这个输出

   Name  Sales  Rank 
   Randy 1596   1
   Raj   1354   2
   Robin  988   3
   Mano   860   4

当我使用max and most 时,它只显示最大值,而大部分对我不起作用。我需要帮助,请任何人帮助我 谢谢

cust = Hash.new

  CSV.foreach(("./test.csv"), headers: true, col_sep: ",") do |row|

    cust.store(row["Name"],row["Sales"])   
  end
  
  print cust

我目前正在尝试使用 Hash,但它保存了最后的数据

【问题讨论】:

  • 绝对需要澄清你到目前为止所做的事情。
  • 我试过数组
  • 我正在尝试使用 Hash,但它正在存储最后的数据
  • 如果您希望 row['Name'] 工作,您的 CSV 需要在第一行包含标题。现在 row['Name'] 为零
  • 是的,我有姓名和销售行

标签: ruby csv


【解决方案1】:

如果要使用 row["COL"] csv 语法,则需要 CSV 中的列名。 此外,您需要使用 += 而不是 = 来添加它们。现在你只是每次都覆盖这个值。

Name,Sales
Randy, 200
Robin, 502
Randy, 200
Raj,   502
Randy, 500      
Robin, 102      
Mano,  220
Raj,   502
Randy, 285
Robin, 385
Randy, 295
Raj,   596
require 'csv'
cust = Hash.new

CSV.foreach(("./data.csv"), headers: true, col_sep: ",") do |row|
  # if key isn't in hash start it at 0
  unless cust.keys.include?(row["Name"])
    cust[row["Name"]] = 0 
  end
  # add the sales (.to_i converts to integer)
  cust[row["Name"]] += row["Sales"].to_i
end

puts "Name Sales Rank"
# Sort by the value not the key. Make it negative so it's descending
# not ascending. 
# each_with_index is just a nice way to count them
cust.sort_by{|k,v| -v}.each_with_index do |(name, sales), i|
  puts "#{name} #{sales} #{i+1}"
end

生产:

Raj 1600 1
Randy 1480 2
Robin 989 3
Mano 220 4

【讨论】:

    【解决方案2】:

    首先,让我们创建一个包含该信息的文件。

    str =<<~_
    Name , Sales
    Randy, 200
    Robin, 502
    Randy, 200
    Raj,   502
    Randy, 500      
    Robin, 102      
    Mano,  220
    Raj,   502
    Randy, 285
    Robin, 385
    Randy, 295
    Raj,   596
    _
    
    FNAME = 'f.csv'
    
    File.write(FNAME, str)
      #=> 157
    

    CSV 文件有一个固定的列分隔符(字符串)。按照惯例,分隔符是逗号,在这种情况下,该文件的内容将如下所示:

    Name,Sales
    Randy,200
    Robin,502
    Randy,200
    Raj,502
    Randy,500      
    Robin,102      
    Mano,220
    Raj,502
    Randy,285
    Robin,385
    Randy,295
    Raj,596
    

    或者,分隔符可以是", ",但这不是所有行的分隔符。第一行在逗号之前包含一个空格,而其他一些行在逗号之后包含两个或多个空格。因此,您应该使用逗号(默认)作为列分隔符,然后在需要时去掉剩余内容的开头和结尾空格。

    我们可以先打开文件创建一个CSV实例。

    require 'csv'
    
    csv = CSV.open(FNAME, headers: true)
      #=> #<CSV io_type:File io_path:"f.csv" encoding:UTF-8 lineno:0 col_sep:",
            " row_sep:"\n" quote_char:"\"" headers:true>
    

    我们会发现csv.class #=&gt; CSVcsv.headers #=&gt; true。后者只是确认我们已经规定文件有标题。由于尚未读取文件中的任何内容,因此不会返回标头本身。一旦读取了标题后的第一行csv.headers,将返回标题数组。您不需要col_sep: ",",因为默认的列分隔符是逗号。

    我们现在读取文件并计算感兴趣的哈希值。

    h = csv.each_with_object(Hash.new(0)) do |csv_row, h|
      name, sales = csv.headers
      h[csv_row[name].strip] += csv_row[sales].to_i
    end
      #=> {"Randy"=>1480, "Robin"=>989, "Raj"=>1600, "Mano"=>220}
    

    作为CSV.included_modules.include?(Enumerable) #=&gt; trueEnumerable#each_with_object 枚举csv 的元素,它们是CSV_Row 的实例(块变量csv_row 的值)并创建一个计数哈希,其形式为方法Hash::new 接受一个参数(默认值)并且没有块。请注意,在计算name #=&gt; "Name "sales #=&gt; " Sales"

    我们现在可以检索标题:

    name, sales = csv.headers.map(&:strip)
      #=> ["Name", "Sales"]
    

    关闭文件是个好主意:

    csv.close
    

    虽然方法 CSV#close 没有记录。


    我们现在可以操纵hheaders 以满足要求。例如,我们可以计算以下内容:

    names, all_sales = h.sort_by { |name, sales| -sales }
                        .map { |name,sales| [name, sales.to_s] }
                        .transpose
      #=> [["Raj", "Randy", "Robin", "Mano"], ["1600", "1480", "989", "220"]]
    
    max_name_len  = [name.size, names.max_by(&:size).size].max
      #=> 5
    max_sales_len = [sales.size, all_sales.max_by(&:size).size].max
      #=> 4
    
    RANK_NAME = "Rank"
    max_rank_len  = [RANK_NAME.size, names.size].max
      #=> 4
    

    然后以格式良好的方式呈现结果。

    puts name.ljust(max_name_len) + ' ' + sales.rjust(max_sales_len) +
      ' ' + RANK_NAME.rjust(max_sales_len)
    (0..names.size-1).each { |i| puts names[i].ljust(max_name_len) + ' ' +
      all_sales[i].rjust(max_sales_len) + ' ' + (i+1).to_s.rjust(max_rank_len) }
    

    这将显示以下内容。

    Name  Sales Rank
    Raj    1600    1
    Randy  1480    2
    Robin   989    3
    Mano    220    4 
    

    String#ljustString#rjust。也可以使用String#%Kernel#sprintf


    CSV 具有内置的转换器(和标头转换器)。如果有人写:

    csv = CSV.open(FNAME, headers: true, converters: :integer)
    

    文件正文中的所有值都将转换为整数。不幸的是,这会将name 字段的值以及sales 字段的值转换为整数,这不是我们想要的。但是,我们可以创建一个自定义转换器,仅将 sales 值转换为整数。这是按如下方式完成的。

    proc = ->(s) { s.match(/ *\d+ */) ? s.to_i : s }
    csv = CSV.open(FNAME, headers: true, converters: proc)
    

    然后我们可能会将csv_row[sales].to_i 更改为csv_row[sales]

    h = csv.each_with_object(Hash.new(0)) do |csv_row, h|
      name, sales = csv.headers
      h[csv_row[name].strip] += csv_row[sales]
    end
      #=> {"Randy"=>1480, "Robin"=>989, "Raj"=>1600, "Mano"=>220}
    

    如果有多个自定义转换器,我们将编写:

    CSV.open(FNAME, headers: true, converters: [proc1, proc2,...])
    

    proc1, proc2,... 是实现自定义转换器的过程。如果只有一个自定义转换器,如这里,我们可以写成converters: procconverters: [proc]


    最后,如果您对 CSV 文件有些生疏,您可以简单地将文件视为普通文件:

    headers, *body = File.readlines(FNAME)
                         .map { |s| s.strip.split(/ *, */) }
      #=> [["Name", "Sales"],
      #    ["Randy", "200"], ["Robin", "502"], ["Randy", "200"],
      #    ["Raj", "502"], ["Randy", "500"], ["Robin", "102"],
      #    ["Mano", "220"], ["Raj", "502"], ["Randy", "285"],
      #    ["Robin", "385"], ["Randy", "295"], ["Raj", "596"]]
    

    因此:

    headers
      #=> ["Name", "Sales"]
    body
      #=> [["Randy", "200"], ["Robin", "502"], ["Randy", "200"],
      #    ["Raj", "502"], ["Randy", "500"], ["Robin", "102"],
      #    ["Mano", "220"], ["Raj", "502"], ["Randy", "285"],
      #    ["Robin", "385"], ["Randy", "295"], ["Raj", "596"]]
    
    h = body.each_with_object(Hash.new(0)) do |(name, sales),h|
      h[name] += sales.to_i
    end
      #=> {"Randy"=>1480, "Robin"=>989, "Raj"=>1600, "Mano"=>220}
    

    然后像以前一样继续。

    【讨论】:

      猜你喜欢
      • 2013-05-12
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 2014-01-02
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多