0

我正在尝试使用 CSV 计算三个数字的平均值并将其输出到单独的文件中。特别是,打开一个文件,取第一个值(名称),然后计算接下来三个值的平均值。对文件中的每个人多次执行此操作。

这是我的 Book1.csv

Tom,90,80,70
Adam,80,85,83
Mike,100,93,89
Dave,100,100,100
Rob,80,70,75
Nick,80,90,70
Justin,100,90,90
Jen,80,90,100

我试图让它输出这个:

Tom,80
Adam,83
Mike,94
Dave,100
Rob,75
Nick,80
Justin,93
Jen,90

我将每个人都放在一个数组中,我可以让它与我编写的基本“伪”代码一起工作,但它不起作用。到目前为止,这是我的代码:

#!/usr/bin/ruby
require 'csv'
names=[]
grades1=[]
grades2=[]
grades3=[]
average=[]
i = 0
CSV.foreach('Book1.csv') do |students|
  names << students.values_at(0)
  grades1 << reader.values_at(1)
  grades2 << reader.values_at(2)
  grades3 << reader.values_at(3)
end

while i<10 do
   average[i]= grades1[i] + grades2[i] + grades3[i]
   i= i + 1
end

CSV.open('Book2.csv', 'w') do |writer|
   rows.each { |record| writer << record }
end

while 循环部分是我最关心的部分。有什么见解吗?

4

1 回答 1

2

如果您有一个要求和的值数组,您可以使用:

sum = array.inject(:+)

如果您将数据结构更改为:

grades = [ [], [], [] ]
...
grades[0] << reader.values_at(1)

然后你可以这样做:

0.upto(9) do |i|
  average[i] = (0..2).map{ |n| grades[n][i] }.inject(:+) / 3
end

有多种方法可以改进您的数据结构,以上是对您的代码影响最小的方法之一。

任何时候你发现自己在写作:

foo1 = ...
foo2 = ...

您应该将其识别为代码异味,并考虑如何将数据组织到更好的集合中。


这是我如何做到这一点的重写。请注意,它适用于任意数量的分数,而不是硬编码为 3:

require 'csv'
averages = CSV.parse(DATA.read).map do |row|
  name, *grades = *row
  [ name, grades.map(&:to_i).inject(:+) / grades.length ]
end
puts averages.map(&:to_csv)
#=> Tom,80
#=> Adam,82
#=> Mike,94
#=> Dave,100
#=> Rob,75
#=> Nick,80
#=> Justin,93
#=> Jen,90

__END__
Tom,90,80,70
Adam,80,85,83
Mike,100,93,89
Dave,100,100,100
Rob,80,70,75
Nick,80,90,70
Justin,100,90,90
Jen,80,90,100
于 2012-04-12T15:25:41.807 回答