Python - 比较文本文件中的列,循环并弹出列表
我有一个文本文件,内容如下:
First col, Second col, Third col, Fourth col,...
类似这样的:
Johnny, Rodgers, ID1, 18th July,...
Johnny, Rodgers, ID1, 18th July,...
Pat, Bryant, ID2, 29th April,...
Pat, Bryant, ID2, 9th May,...
Jim, Williams, ID3, 10th March,...
Jim, Williams, ID3, 17th March,...
Jim, Williams, ID3, 21st March,...
etc
我想检查第三列是否有重复的值,如果有的话,再看看第四列在这些重复的行中是否也相同。如果第三列和第四列的值都相同,就删除这两行(整行都删除);如果第四列的值不同,就把结果保存下来。最后打印或保存这个结果。
具体来说,
* 如果第1行和第2行在第三列的值相同,并且在第四列的值也相同,就删除这两行。
* 如果第3行和第4行在第三列的值相同,但在第四列的值不同,就打印这两行,并计数加1。
* 如果第5行、第6行和第7行在第三列的值相同,但在第四列的值不同,也打印这些行,并计数加1。
所以执行后,结果应该是这样的:
Pat, Bryant, ID2, 29th April,...
Pat, Bryant, ID2, 9th May,...
Jim, Williams, ID3, 10th March,...
Jim, Williams, ID3, 17th March,...
Jim, Williams, ID3, 21st March,...
counter = 2 #Number of different ID present
我的想法是创建两个列表来存储这些行,但我在设置目标和同时比较其他列时遇到了困难。我还需要循环和弹出(pop)操作,但我现在的逻辑做得不好。
val = []
duplicated = []
with open('file.txt', 'rt') as myf.
for line in myf:
col = line.stip():split(',')
if col[2] not in val:
val.append( THE ROW HERE ) #How to copy and parse the row?
else:
duplicated.append( THE ROW HERE ) #Same question
#Comparisons
for x in value:
if x in dupl:
value.pop(x)
dupl.pop(x)
counter = len(val) #Counter of total cases not erased
val.extend(duplicated)
### I would like to print the whole set of rows ordered by the 3rd col
for element in val:
print element
print "counter of cases: " , counter
任何帮助和改进我代码的建议都非常欢迎。
2 个回答
1
我从你的示例代码开始,假设需要合并和删除的行是相邻的。我简单地保留上一行的值来进行比较,并可选择性地添加最后一行。
我使用一个集合来统计不同的ID。
我还对保留的行进行了排序,按照第三个字段和第四个字段(用当前地区的完整月份名称表示的日期)进行排序。
在你的示例中测试后,输出结果正是你所要求的,即使输入的行顺序被打乱,只要要删除的两行是相邻的。
代码如下:
import re
import datetime
val = []
old = None
oldcount = 0
oldcols = None
counter = 0
ids = set()
with open('file.txt', 'rt') as myf:
for line in myf:
cols = line.strip().split(',')
if (old is not None) and (oldcols[2] == cols[2]) \
and (oldcols[3] == cols[3]):
oldcount += 1
else:
if oldcount == 1:
val.append(old)
ids.add(cols[2])
old = line.strip()
oldcount = 1
oldcols = cols
if oldcount == 1:
val.append(old)
ids.add(cols[2])
### I would like to print the whole set of rows ordered by the 3rd col
rx = re.compile('\s*([ 0-9]{2}).. *(\w*)')
val.sort(key = lambda x: datetime.datetime.strptime(
rx.sub('\g<1> \g<2>',x.split(',')[3]),'%d %B'))
val.sort(key = lambda x: x.split(',')[2])
for element in val:
print (element)
print ("counter of cases: " , len(ids))
1
假设这些数据总是相邻的,使用你的示例数据:
import csv
with open(fn, 'r') as fin:
reader=csv.reader(fin, skipinitialspace=True)
header=next(reader)
data={k:[] for k in header}
for row in reader:
row_di={k:v for k,v in zip(header, row)}
if (all(len(data[e]) for e in header)
and row_di['Third col']==data['Third col'][-1]
and row_di['Fourth col']==data['Fourth col'][-1]):
for e in header:
data[e].pop()
else:
for e in header:
data[e].append(row_di[e])
>>> data
{'Second col': ['Bryant', 'Bryant', 'Williams', 'Williams', 'Williams'], 'First col': ['Pat', 'Pat', 'Jim', 'Jim', 'Jim'], 'Fourth col': ['29th April', '9th May', '10th March', '17th March', '21st March'], 'Third col': ['ID2', 'ID2', 'ID3', 'ID3', 'ID3'], '...': ['... ', '... ', '... ', '... ', '...']}
按照你的格式打印出来:
unique_ids=set(data['Third col'])
while True:
try:
print ', '.join([data[e].pop(0) for e in header])
except IndexError:
break
print 'Unique IDs:', len(unique_ids)
打印结果是:
Pat, Bryant, ID2, 29th April, ...
Pat, Bryant, ID2, 9th May, ...
Jim, Williams, ID3, 10th March, ...
Jim, Williams, ID3, 17th March, ...
Jim, Williams, ID3, 21st March, ...
Unique IDs: 2
注意事项:
- 处理csv数据时,通常使用csv模块会更好;
- 可以用
set(iterable)
来获取可迭代对象中唯一条目的数量; - 如果你的数据量很大,可以考虑使用包含双端队列(deque)的字典,而不是包含列表的字典。因为双端队列在弹出元素时速度更快,而这个实现依赖于弹出操作。