TL; DR:你能否可靠地遍历csv对象本身,或者使用(如果/不是)对抗它?
所以我遇到了一个奇怪的问题。它似乎是断断续续的,但那仅仅是因为我不知道发生了什么。我确信这是一个真正的原因。
我有以下内容:
import os
import csv
csv_old = 'vendor_old.csv'
csv_new = 'vendor.csv'
csv_sftp = 'vendor_sftp.csv'
def check_vendor_length():
with open(csv_old, 'r') as t_old:
vendor_old = csv.reader(t_old, delimiter = ',')
all_vendor_old = next(vendor_old)
len_vendor_old = len(all_vendor_old)
return len_vendor_old
def check_vendor_old():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'w', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_old = []
row_vendor_old = next(vendor_old)
row_vendor_old.insert(csv_len, 'action')
all_vendor_old.append(row_vendor_old)
for row_vendor_old in vendor_old:
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
vendor_sftp.writerows(all_vendor_old)
def check_new():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'a', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_new = []
row_vendor_new = next(vendor_new)
row_vendor_new.insert(csv_len, 'action')
for row_vendor_new in vendor_new:
all_vendor_new.append(row_vendor_new + ['add'])
vendor_sftp.writerows(all_vendor_new)
因此,第一个函数将旧CSV与新CSV进行比较。如果旧行中的行不在新行中,则应将它们标记为删除。它们是针对将要向供应商提供SFTP的(新的新)CSV的书面形式。
第二个功能只获取新CSV中的所有数据,并将其附加到SFTP CSV。
发生的事情是昨晚生成的SFTP CSV与所有内容都重复,唯一的区别是首先是'删除'条目,然后在所有这些条目之后,相同的行,但是使用“添加”代替“删除”。
但这并不总是发生。在测试中,它按预期工作。没有重复。但出于某种原因,昨晚的SFTP还有所有重复。由此处理的CSV只有大约10列,大约5100行。
奇怪的是,当我把它缩小一点以至于我只用了大约2-300行时,我遇到了同样的问题。没有显示额外的代码,但基本上,在创建SFTP CSV之后,旧的CSV被删除,新的CSV被重命名为旧的CSV名称。然后,第二天,当新CSV被转储到目录中时,脚本可以再次运行。冲洗并重复。
我们可以确定的最接近的是,可能通过 CSV OBJECT(vendor_new = csv.reader(t_new,delimiter =','))进行迭代,不知怎的。所以我所做的就是修改check_vendor_old函数,以便先将新CSV读入列表,然后for循环检查旧CSV行与新CSV列表的对比:
def check_vendor_old():
with open(csv_old, 'r') as t_old, open(csv_new, 'r') as t_new, open(csv_sftp, 'w', newline = '') as t_sftp:
vendor_old = csv.reader(t_old, delimiter = ',')
vendor_new = csv.reader(t_new, delimiter = ',')
vendor_sftp = csv.writer(t_sftp, delimiter = ',')
all_vendor_old = []
row_vendor_old = next(vendor_old)
row_vendor_old.insert(csv_len, 'action')
all_vendor_old.append(row_vendor_old)
################ NEW STUFF HERE ################
# Create list comprised of new vendor.csv rows
list_vendor_new = []
for row in vendor_new:
list_vendor_new.append(row)
# print(list_vendor_new)
################ NEW STUFF HERE ################
for row_vendor_old in vendor_old:
if row_vendor_old not in list_vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
vendor_sftp.writerows(all_vendor_old)
所以这一切似乎都按预期工作......但我想我们会看到。
所以我的问题是,在阅读csv阅读器文档时,我是否遗漏了一些内容?你能不能可靠地遍历csv对象本身,或者使用[if / not in]来对付它?它似乎在测试期间起作用,但显然昨晚没有按计划进行。
更新
我发现vendor_new.seek(0)
不起作用(因为vendor_new
类是_csv.reader
,它没有搜索方法),但t_new
(我将CSV打开为)是_io.TextIOWrapper
,它有搜索方法。
所以我想,如果我这样做:
def check_vendor_old():
...
for row_vendor_old in vendor_old:
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
t_new.seek(0)
这可能更接近我想要的。 (如果我真的想要使用csv.reader对象而不是列表。)
答案 0 :(得分:0)
您在原始代码中的问题是:
if (!Arrays.asList("yes", "no", "foo", "bar").contains(name_answer)) {
现在,def check_vendor_old():
...
for row_vendor_old in vendor_old:
# !!! - this is not doing what you think its doing ...
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
不是列表......它是一个迭代器。检查迭代器中是否存在某些内容包括推进它直到找到匹配项。下次执行此操作时,它将从剩余迭代器的位置开始。
举一个例子,考虑一下这个迭代器:
vendor_new
是>>> r = (x for x in range(10))
吗?
5
当然是。但是>>> print(5 in r)
True
在其中吗?
3
不......不是,因为在找到>>> print(3 in r)
False
时,我们将迭代器推进到5
之外。如果将迭代器结晶到列表,问题就会消失:
5
答案 1 :(得分:0)
所以我决定这样做:
%PDF-1.4
%âãÏÓ
3 0 obj
<</Type /Page
/Parent 1 0 R
/MediaBox [0 0 595.280 841.890]
/TrimBox [0.000 0.000 595.280 841.890]
/Resources 2 0 R
/Group << /Type /Group /S /Transparency /CS /DeviceRGB >>
/Contents 4 0 R>>
endobj
4 0 obj
<</Filter /FlateDecode /Length 687>>
stream
¡Ï+ëdtüG>KTx´D‰ëE-®Š:øÙ£Þ/íÔÑüÀ3VƒåmzûÙrEë<Å-Å~õÊ2RÏ=ÔÈša牮j»ýqE©{€cSú¡¹S:9RXC q*^w2 E»+`~ÉvÝýwkS§?l¢#çöð«çPÂK.
YÓCR‰˜£…ôÏM°xÑçõ©z+®¢áüØêÂ[ „
-áûþr%²Ü¯6ß8VÅ^jªDA”öIó¦ì üqœæ6é½òØX
ŽiÙ,hLkv†½uVöüï.h8Rf3cIú±¢õF(½ªêæp´¸·åYÇíÎÊ?xŠä4sð¾]ÆÝ÷µ ›å+DøC›‚6C¾7K¥8܇¹çGÈ`¤ŸçÚ/LO+çôsLÕ Tß¡‰Ô•‰Äµ!ôÐç{ê/ºf;Á=¢V€}…=Á£+‰}¨Q„.?øÁ†Ÿúòßê¨Ò€/!Û[Âò#¼«þÏþA?�Uc™–HÄ,‚m¨œ¸„]7P€¿V 9ËŸª*}{1+ŒÛLݧø›‘öw¬PêqÙsé—.ß÷D7ª3Sæºf¶"ºåð~E‹|Ä{mϯaâ´•0|Cw™U};ÊÌ4ÝùfÚE¨ïåsWÒPL6ŸGx™§7þEU\ž7võŸÜHªŽ;>óaPÂs¡ÞÙ˜xüÅÎIhÖD䌷8ó�Äò‚øèF¬BU×Ìt¤³æNµµe÷)LÖ.CõåvÒ4–Sb:wxlÜ–´ã` wÇ"c‰>O™Ž-óéúëAIM¹
在每个循环开始时将def check_vendor_old():
...
for row_vendor_old in vendor_old:
t_new.seek(0) ### Added this here
if row_vendor_old not in vendor_new:
all_vendor_old.append(row_vendor_old + ['remove'])
位置重置为0。我认为它起初并不起作用,因为它需要很长时间才能运行,但这只是因为它在一个CSV中迭代5000行以及在另一个CSV中迭代5000行,而不是像我的一样通过单行原始的坏代码是第一次工作。
所以,我正在给@donkopotamus回答到我的帖子,因为该回复直接回答了我最初的问题,而且我无法找到 my 他们在他们的帮助下回答,但我会说这可能是我正在寻找的答案。