如何排序和删除数组中的重复项?

时间:2013-07-25 13:38:56

标签: ruby

我必须比较两个由电子商务填充的Csv文件。这些文件总是相似的,只是较新的文件具有不同数量的项目,因为目录每周都会更改。

CSV文件示例:

sku_code, description, price, url    
001, product one, 100, www.something.com/1 
002, prouct two, 150, www.something.com/2

通过比较在不同日期提取的两个文件,我想生成一个已停产的产品清单和另一个已添加的产品清单。

我的索引应该是Sku_code,它在目录中是单义的。

我一直在使用this code from stackoverflow

#old file
f1 = IO.readlines("oldfeed.csv").map(&:chomp)
#new file
f2 = IO.readlines("newfeed.csv").map(&:chomp)

#find new products
File.open("new_products.txt","w"){ |f| f.write((f2-f1).join("\n")) }

#find old products
File.open("deleted_products.txt","w"){ |f| f.write((f1-f2).join("\n")) }

我的问题

效果很好,除了一种情况:当sku_code之后的一个字段发生变化时,产品被认为是“新的”(例如:价格的变化),即使对于我的需要,它也是相同的产品。

仅比较sku_code而不是整行的最明智的方法是什么?

3 个答案:

答案 0 :(得分:2)

无需使用CSV库,因为您对实际值不感兴趣(sku_code除外)。我将每行放入一个以sku_code为键的哈希值,比较sku_codes,然后从这些哈希值中检索值。

#old file
f1 = IO.readlines("oldfeed.csv").map(&:chomp)
f1_hash = f1[1..-1].inject(Hash.new) {|hash,line| hash[line[/^\d+/]] = line; hash}
#new file
f2 = IO.readlines("newfeed.csv").map(&:chomp)
f2_hash = f2[1..-1].inject(Hash.new) {|hash,line| hash[line[/^\d+/]] = line; hash}

#find new products
new_product_keys = f2_hash.keys - f1_hash.keys
new_products = new_product_keys.map {|sku_code| f2_hash[sku_code] }

#find old products
old_product_keys = f1_hash.keys - f2_hash.keys
old_products = old_product_keys.map {|sku_code| f1_hash[sku_code] }

# write new products to file
File.open("new_products.txt","w") do |f|
  f.write "#{f2.first}\n"
  f.write new_products.join("\n")
end

#write old products to file
File.open("deleted_products.txt","w") do |f|
  f.write "#{f1.first}\n"
  f.write old_products.join("\n")
end

每个csv文件的第一行只包含列名。所以我跳过了每个csv文件的第一行(f1[1..-1]),并在编写新文件(f.write "#{f1.first}\n")时添加了它。

测试了两个虚构的csv文件。


编辑:使用old_products意外计算new_product_keys,这是一个错字。感谢那些试图编辑我的答案的人(但不幸的是被拒绝了)。

答案 1 :(得分:0)

 require 'csv'
 #I'm really hungover
 DOA = 'oldfeed.csv'
 DOB = 'newfeed.csv'
 #^this is where your files are located

DOC = 'finished_product.csv'
#this little guy here is a csv file that has the unique values
#you dont need to create this file, ruby will make it for you


holder_1 = CSV.read(DOA)
holder_2 = CSV.read(DOB)
#we just put both csv files into an array
#way too early to be up
#assuming the Sku_code is the first number '001'
#holder_1[0][0] = 001
#holder_1[1][0] = 002    

这应该让你感动,你需要两个while循环和一个if语句,你需要更多的信息吗?或者你还好吗?

如果您希望csv文件向您显示结果,那么使用csv gem会更容易。

答案 2 :(得分:0)

假设您没有很大的性能问题,我认为您希望争取最少量的代码。即使性能是一个问题,我也会从最简单的方法开始,并根据您的需求进行改进。

我认为使用CSV gem是个不错的主意,因为编写代码要少一些。也就是说,这是另一种解决这个问题的方法。请注意,下面的diff函数适用于数组或散列,并且与键的定义方式无关。它在内部使用一个数组进行键查找,但更改它以使用哈希是很简单的。

l1a = "001, product one, 100, www.something.com/1"
l2 = "002, prouct two, 150, www.something.com/2"
l1b = "001, product one, 120, www.something.com/1"
l3 = "003, product three, 100, www.something.com/1"
l4 = "004, product four, 100, www.something.com/1"

file_old = [l1a, l2, l3]
file_new = [l1b, l2, l4]

sku = -> (record) do
  record.split(',')[0]
end

def diff(set1, set2, keyproc)
  set2_keys = set2.collect {|e| keyproc.call(e)}
  set1.reject {|e| set2_keys.include?(keyproc.call(e))}
end

puts diff(file_old, file_new, sku)
# => "003, product three, 100, www.something.com/1"
puts diff(file_new, file_old, sku)
# => "004, product four, 100, www.something.com/1"