我正在尝试编写一个Ruby脚本来对一堆CSV文件进行排序。所以我正在使用CSV.read('file.csv')将文件读入变量中,我需要扫描其中一列以检查其中一个值是否与另一个值匹配,或者是否匹配两个或更多值的总和。 我的CSV看起来像:
title,day,total,flag
Cats,Friday,13,0
Cats,Friday,20,1
Cats,Friday,7,0
Cats,Friday,20,0
Cats,Tuesday,23
Cats,Tuesday,11,
Cats,Tuesday,5
Cats,Tuesday,6
Dogs,Monday,12
所以我有这个相当复杂的解决方案,循环遍历CSV数组数组并存储数组中每个匹配标题的索引以及另一个数组中看到标题的每周匹配日的索引。现在我坚持的部分是找到哪个值匹配另一个/另一个的总和。 例如。周五20和周二11
到目前为止我所拥有的是:
fullfile = CSV.read('mycsv.csv', "r:ISO-8859-1")
i = 1
main = 1
ctitle = fullfile[1][0] ## Set current title to the first line in the CSV
mon = Array.new ##
tue = Array.new ## Arrays to store
wed = Array.new ## the indexes for
thu = Array.new ## days of the week
fri = Array.new ## of a title
sat = Array.new ##
sun = Array.new ##
mi = 0 ## index variables
ti = 0 ## for each day array
wi = 0
thi = 0
fi = 0
sai = 0
sui = 0
while main < fullfile.count ## Main loop through entire file
while fullfile[i][1] == ctitle ## Loop to find matching titles
case fullfile[i][2] #check the current title
when "Tuesday" #and store the index in
tue[ti] = i #the appropriate day array
ti = ti + 1
when "Friday"
fri[fi] = i
fi = fi + 1
end
i = i + 1
end
## But now that I have the indexes
## how do I search fullfile[tue[ti][2]
## looking for matches
main = main + 1
if fullfile[main] == fullfile.last # reset the main loop and
cmovie = fullfile[main][1] # move on to the next item
main = 0
i = 0
end
end
所以现在我的计划是使用Title和Day的索引再次循环,找到匹配的数字及其索引,以便我可以对该行进行适当的更改,但我不知道如何做到这一点。
编辑:
最终结果是编辑'flag'列并在当天匹配的数字旁边加1,其余为0。 例如,星期五的'总'猫是13,20,7,20。由于7 + 13 = 20和/或有2x 20,我需要在星期五标志20的其中一个,星期五的剩余时间是0的等;
title,day,total,flag
Cats,Friday,13,0
Cats,Friday,20,1
Cats,Friday,7,0
Cats,Friday,20,0
然后在星期二为Cats做同样的事情,在这种情况下是23,11,5,6。所以那里没有匹配的数字,但是5和6的总和与星期二的第2行匹配,使得我想要的数字为11。因此,我将该行标记为总数为11,其余的猫周二将为0
Cats,Tuesday,23,0
Cats,Tuesday,11,1
Cats,Tuesday,5,0
Cats,Tuesday,6,0
一旦我完成周一至周日的Cats,我会对Dogs和Title列中的任何其他内容做同样的事情。
答案 0 :(得分:0)
嗯,我没有意识到你想要实现什么,但我可以帮助你开始。
csv = CSV.read('/tmp/csv.csv').map do |e|
e.take(3)
end.inject({}) { |memo, e|
((memo[e[1]] ||= {})[e[0]] ||= []) << e[2]
memo
end
会给你:
=> {
"Friday" => {
"Cats" => [
[0] "13",
[1] "20",
[2] "7",
[3] "20"
]
},
"Monday" => {
"Dogs" => [
[0] "12"
]
},
"Tuesday" => {
"Cats" => [
[0] "23",
[1] "11",
[2] "5",
[3] "6"
]
},
"day" => {
"title" => [
[0] "total"
]
}
}
我很确定从这里走得更远更容易。希望它有所帮助。
无论您是否提供所需的输出,我都可以尝试进一步引导它。
答案 1 :(得分:0)
根据您的评论,您可以执行此操作
require 'csv'
csv = CSV.read('mycsv.csv', "r:ISO-8859-1", headers: true)
groups = csv.group_by { |row| [row['title'], row['day']] }
groups.each do |key, rows|
# find two rows with matching totals, pick the first
match, _ = rows.combination(2).find { |r1, r2| r1['total'].to_i == r2['total'].to_i }
# else, find three rows where one total is the sum of the other two
unless match
_, _, match = rows.combination(3).find do |rs|
rs.sort_by! { |r| r['total'].to_i }
rs[0]['total'].to_i + rs[1]['total'].to_i == rs[2]['total'].to_i
end
end
match["flag"] = 1 if match
end
# save
File.open('foo.csv', 'w') { |f| f.write(csv.to_s) }