比如有这样的一个 CSV 文件:
有什么比较优雅的方法可以变成这样:
{
"A": ["123", "1223", "12343", "122XX33"],
"B": ["678","612378", "67XX8"],
"C": ["100", "1000"]
}
CSV 应该有个 header 的,可以利用inject
,像这样:
data = [
{h1: 'A', h2: '123'},
{h1: 'A', h2: '1223'},
{h1: 'A', h2: '12343'},
{h1: 'A', h2: '123XX33'},
{h1: 'B', h2: '678'},
{h1: 'B', h2: '612378'},
{h1: 'B', h2: '67XX8'},
{h1: 'C', h2: '100'},
{h1: 'C', h2: '1000'}
]
data.inject({}) { |r, e| r[e[:h1]] = Array(r[e[:h1]]) << e[:h2]; r }
#=> {"A"=>["123", "1223", "12343", "123XX33"], "B"=>["678", "612378", "67XX8"], "C"=>["100", "1000"]}
# or
data.map{|x| Hash[*x.values]}.inject(&lambda{|x,y| x.merge(y){ |_, o, n| [o, n].flatten }})
#=> {"A"=>["123", "1223", "12343", "123XX33"], "B"=>["678", "612378", "67XX8"], "C"=>["100", "1000"]}
可以先用数组的前一个元素做 group_by,然后用 map! 方法将后一个元素做 replace:
data = [['A', '123'], ['A', '1223'], ['A', '12343'], ['A', '122XX33'], ['B', '678'], ['B', '612378'], ['B', '67XX8'], ['C', '100'], ['C', '1000']]
data.group_by(&:first).each{|_, v| v.map!(&:last)}
# => {"A"=>["123", "1223", "12343", "122XX33"], "B"=>["678", "612378", "67XX8"], "C"=>["100", "1000"]}
h = {}
data.each {|a, b| (h[a] ||= []) << b }
如果想要奇技淫巧,可以用 Sqlite 的 CSV mode ...
textql -header -sql "select name, group_concat(value) from csv group by name" csv.txt