【问题标题】:Python - compare columns in a text file, loop and pop listsPython - 比较文本文件、循环和弹出列表中的列
【发布时间】:2014-10-04 08:50:38
【问题描述】:

我有一个如下的文本文件

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   

我想检查第 3 列是否有重复,在这种情况下,请检查第 4 列是否与第 3 列中的重复行相同。如果第 3 列和第 4 列也相同,则删除两行(整行),如果第 4 列不同,则存储结果。之后打印/存储结果。

这是,
* 如果第 1、2 行在第 3 列具有相同的值,在第 4 列也具有相同的值,则删除这两行
* 如果第 3 行和第 4 行在第 3 列具有相同的值而在第 4 列具有不同的值,则打印行并计数 +1
* 如果第 5、6 和 7 行在第 3 列具有相同的值而在第 4 列具有不同的值,则打印行并计数 +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

我的想法是制作两个列表并在那里存储行,但我没有成功设置目标并同时比较其他列。我还需要循环和弹出我当前的逻辑,但我做得不好。

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

非常欢迎帮助和建议改进我的编码。

【问题讨论】:

  • 公共行(要删除的行)是否总是相邻,或者是否有必要将所有内容都保留在内存中直到文件结束?
  • @SergeBallesta 嗨!它们总是相邻的。我不知道会有多少重复的情况。通常会有 2 个连续的行进行比较,但它们可能更多的是一个未确定的值(超过 4 行真的很奇怪,但有可能)。

标签: python list python-2.7 text ordereddictionary


【解决方案1】:

我从您的示例代码开始,并假设要合并和删除的行是相邻的。我只是保留前一行的值进行比较,并可选地添加最后一行。

我使用一组来计算不同的 id。

我还对第 3 个字段和第 4 个字段的保留行进行了排序,作为当前语言环境中月份全名的 dat。

在您的示例中测试,输出是您要求的,即使输入行被打乱,只要要删除的 2 行是相邻的。

代码是:

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,但我会在接受一个答案之前调查另一个答案。问候!
【解决方案2】:

假设它们总是相邻的,并使用您的示例数据:

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

注意事项:

  1. 对于 csv 数据,通常最好使用 csv module
  2. 使用set(iterable) 获取可迭代项中唯一条目的数量;
  3. 如果您有大量数据,您可以考虑使用deques 的字典而不是列表的字典。使用此实现所依赖的 pop,双端队列要快得多。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    相关资源
    最近更新 更多