2012-03-07 15 views
3

私は処理する必要があるいくつかのCSVデータを持っており、重複したものと一致する方法を見つけ出すのに問題があります。ruby​​ CSV重複行解析

データビットのようになります。

line id name item_1 item_2 item_3 item_4 
1  251 john foo  foo  foo  foo 
2  251 john foo  bar  bar  bar 
3  251 john foo  bar  baz  baz 
4  251 john foo  bar  baz  pat 

線1-3は、この場合、重複しています。この場合

line id name item_1 item_2 item_3 item_4 
5  347 bill foo  foo  foo  foo 
6  347 bill foo  bar  bar  bar 

のみライン5重複

line id name item_1 item_2 item_3 item_4 
7  251 mary foo  foo  foo  foo 
8  251 mary foo  bar  bar  bar 
9  251 mary foo  bar  baz  baz 

あり、ここでのパターンは、新しい「項目」 前の行を追加した場合のライン7及び8はとても基本的に重複

あります重複しています。 私は関係なく、彼らは

を持っているどのように多くのアイテムの私はRubyは、次のように1.9.3使用していますが、それぞれの人のための単一の行で終わるしたい:

require 'csv' 
puts "loading data" 
people = CSV.read('input-file.csv') 

CSV.open("output-file", "wb") do |csv| 
    #write the first row (header) to the output file 
    csv << people[0] 
    people.each do |p| 
     ... logic to test for dupe ... 
     csv << p.unique 
    end 
end 
+0

"複製"という意味を明確にすることはできますか?私はここで正しい単語が使われているかどうかはわかりません。なぜなら、重複は通常、データの正確なコピーを意味します。したがって、1行は重複することはできませんが、1行は別の行の複製になります。しかし、あなたの例では、重複する行については言及していないので、データと関係がありますが、意味が分かりません。 –

+0

ええ、私は一意であると思いますか凝縮されているか何か:)混乱のために申し訳ありません – sysconfig

+0

あなたは人々のユニークなリストを探していますか、それともそれらのアイテムのリストを探していますか?項目のリストによって行が重複しているかどうかを判断するルールは何ですか?結果はファイル内の行の順序に依存しますか? –

答えて

3

まず、コードにわずかなバグがあります。代わりに:

csv << people[0] 

あなたがループコードを変更したくない場合は、次の操作を実行する必要があります:

csv << people.shift 

、以下のソリューションは、人の最初のオカレンスを追加します(idが一意であると仮定しているので)idによって決定された後続の重複を破棄します。あなたの重複レコードが常に直接、元をたどる場合は、よりパフォーマンスの高いソリューションがあることが

require 'csv' 
puts "loading data" 
people = CSV.read('input-file.csv') 
ids = [] # or you could use a Set 

CSV.open("output-file", "wb") do |csv| 
    #write the first row (header) to the output file 
    csv << people.shift 
    people.each do |p| 
    # If the id of the current records is in the ids array, we've already seen 
    # this person 
    next if ids.include?(p[0]) 

    # Now add the new id to the front of the ids array since the example you gave 
    # the duplicate records directly follow the original, this will be slightly 
    # faster than if we added the array to the end, but above we still check the 
    # entire array to be safe 
    ids.unshift p[0] 
    csv << p 
    end 
end 

注意、あなただけの最後のオリジナルIDを維持し、全体ではなく、アレイに含めるよりも、現在のレコードのidをチェックする必要があります。入力ファイルに多数のレコードが含まれていない場合、その差はごくわずかです。あなたは、人がIDと名前で識別された各人物、関連付けられたユニークなアイテムのリストを取得しようとしているよう

require 'csv' 
puts "loading data" 
people = CSV.read('input-file.csv') 
previous_id = nil 

CSV.open("output-file", "wb") do |csv| 
    #write the first row (header) to the output file 
    csv << people.shift 
    people.each do |p| 
    next if p[0] == previous_id 
    previous_id = p[0] 
    csv << p 
    end 
end 
+0

これは私が最終的に実装を終えたのとほとんど同じです。すべての提案に感謝します。 – sysconfig

0

あなたは「UNIQ」

を使用することができます
irb(main):009:0> row= ['ruby', 'rails', 'gem', 'ruby'] 
irb(main):010:0> row.uniq 
=> ["ruby", "rails", "gem"] 
or 

row.uniq! 
=> ["ruby", "rails", "gem"] 

irb(main):017:0> row 
=> ["ruby", "rails", "gem"] 

irb(main):018:0> row = [1,  251, 'john', 'foo',  'foo',  'foo',  'foo'] 
=> [1, 251, "john", "foo", "foo", "foo", "foo"] 
irb(main):019:0> row.uniq 
=> [1, 251, "john", "foo"] 
+1

これは 'Array'に当てはまります。私はCSVにそのような方法があることを願っています。 – Marcos

1

ですね:次のようになります

{ 
    [251, "john"] => ["bar", "bat", "baz", "foo"], 
    [347, "bill"] => ["bar", "foo"] 
} 

と最長の項目の配列は、あなたですどのくらいを示していますmaxitems:これはあなたのような構造をあげる

peoplehash = {} 
maxitems = 0 
people.each do |id, name, *items| 
    (peoplehash[[id, name]] ||= []) += items 
peoplehash.keys.each do |k| 
    peoplehash[k].uniq! 
    peoplehash[k].sort! 
    maxitems = [maxitems, peoplehash[k].size].max 

:そうです場合は、このような何かを行うことができますあなたが必要とするものは何でも使用できます。