Python 3:检查迭代器的下一个值而不进行迭代
Posted
技术标签:
【中文标题】Python 3:检查迭代器的下一个值而不进行迭代【英文标题】:Python 3: Checking next value of an iterator without iterating 【发布时间】:2015-11-16 13:49:55 【问题描述】:对于一个项目,如果下一行某列中的值等于当前行同一列中的值,我需要检查一个 csv 文件。我正在使用字典 csv 阅读器,即阅读器中的每一行都是一个字典文件。我可以通过使用列标题作为键来访问某一行的值:row[header] = value
。
我当前代码的精简版如下所示:
import csv
with open(os.path.abspath(path_to_file), "r") as f:
reader = csv.DictReader(f, dialect='excel')
for row in reader:
current_row = row
next_row = reader.__next__()
if current_row[column] == next_row[column]:
dosomething()
这里的问题当然是我使用__next__()
跳过了下一次迭代,即
(1) 我进入循环;行 = 行 1
(2) current_row = row1, next_row = row2
(3) 我进入循环的下一次迭代; row = row3 因为我使用了__next__()
。 current_row = row3, next_row = row4
在这个例子中,我永远不会检查row2 == row3
。
是否可以在不迭代迭代器对象的情况下检查下一行的值?
或者,是否有与__next__()
相反的方法,使迭代器后退一步?
请注意:我将当前值与下一个值进行比较,而不是当前值到 last 值,因为我不知道我正在阅读的文件有多长。我必须将文件的最后一行与其他文件不同,所以我必须检查reader.__next()__
以查看是否有最后一行。
【问题讨论】:
我怎样才能读取带有csv.reader
的最后一行而不读取它之前的所有其他行?最后,我将不得不对迭代器的所有元素进行两次迭代。那,或者我误解了你。
'last'/'previous' 行是刚刚读取的行(在最后一个 next'ing 之前)。
【参考方案1】:
您的要求与内置迭代器的想法相冲突。所以我建议你将你的循环封装在自定义迭代器中。 想法是从原始迭代器中产生两个值,最后一行的下一个值为 None。
【讨论】:
【参考方案2】:我不知道这是否可行,但它适用于 android
reader = csv.DictReader(f, dialect='excel')
reader2 = csv.DictReader(f, dialect='excel')
for row in reader:
current_row = row
for row2 in reader2
next_row = reader2.__next__()
if current_row[column] == next_row[column]:
dosomething()
continue
【讨论】:
【参考方案3】:就个人而言,假设您的场景限制允许,我会回顾而不是向前看:
it = iter(reader)
prev_row = it.next()
while True:
try:
cur_row = it.next()
if cur_row[column] == prev_row[column]:
dosomething()
prev_row = cur_row
except StopIteration:
break
【讨论】:
【参考方案4】:试试itertools
pairwise
食谱。更通用的解决方案是 tee
您的迭代器(这是成对配方使用的)。另一种可能性是创建一个具有 cur 和 next 变量并产生所需值的函数(基本上是 pairwise 所做的,但您可以使其产生 CSV 中的字段而不是整行)。
来自https://docs.python.org/2/library/itertools.html
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
我认为pairwise 可以满足您的所有需求,因此无需对您自己的生成器函数或tee
大惊小怪。
reader = csv.DictReader(f, dialect='excel')
for current_row, next_row in pairwise(reader):
if current_row[column] == next_row[column]:
dosomething()
请意识到,如果您有一个包含 n
项的迭代,那么将有成对的 n-1
项。
【讨论】:
我不了解您的解决方案中的一些内容。首先,在 Python 3 中没有itertools.izip
方法,我必须使用 itertools.zip
代替。不过,在这种情况下,这似乎不是问题。当current_row
是阅读器中的最后一项时,next(b, None)
应该为next_row
返回一个None
对象。如果我使用pairwise(reader)
遍历阅读器并在每个步骤中打印current_row
和next_row
,则循环在到达元组(倒数第二行,最后一行)时停止,但我需要在 for 循环中检查下一行是否是阅读器中的最后一行。
只需将 izip 替换为 map
我不知道地图在这里有什么用处。无论如何,我使用了建议的pairwise
函数,并进行了一些调整以检查循环的最后一行阅读器outside。现在我有一些重复的代码行,但一切都按预期工作。谢谢。【参考方案5】:
由于字典必须保留唯一键(因此不能附加具有相同键的行)并且csv.DictReader
对象不可下标(因此不能引用列或行号),请考虑将 csv 数据读入 列表然后将行与后续行进行比较:
import csv
with open(os.path.abspath(path_to_file), "r") as f:
reader = csv.reader(f)
# APPEND READER LINES INTO LIST
csvList = []
for row in reader:
csvList.append(row)
# ITERATE THROUGH LIST, CHECK AGAINST NEXT ROW
for i in range(len(csvList) - 1):
# FIND THE COLUMN NUMBER (BELOW USES 1)
if (csvList[i][1] == csvList[i + 1][1]):
doSomething()
【讨论】:
【参考方案6】:def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
(sy,None) 或 (sy,"") 将是最后一个元组的唯一逻辑可能性,因为值从队列中一次弹出一个,直到迭代结束。
“一旦 tee() 进行了拆分,原始的 iterable 不应在其他任何地方使用;否则,在不通知 tee 对象的情况下,iterable 可能会前进。”
【讨论】:
以上是关于Python 3:检查迭代器的下一个值而不进行迭代的主要内容,如果未能解决你的问题,请参考以下文章