2015-07-21 50 views
0

我收到了一个从TSV/CSV文件收集数据的循环问题。 问题是我检查用户标识符是否在我的tsv文件中,以及是否只是进行常规打印。但事情是它不加起来。运行后停止TSV/CSV文件循环运行

让我用,我有现在直到代码解释一下:

import csv 
with open("source/to/file.tsv") as tsvfile: 
     tsvreader = csv.reader(tsvfile, delimiter="\t") 
     for i in range(1,10): 
      for columns in tsvreader: 
       userid = 1 
       column1, column2, column3 = columns 
       if userid == int(column1): 
        print("userid:", userid,"result: ", int(column1), int(column2), int(column3)) 
        userid += 1 

每当我运行此代码将输出:

-- userid: 1 result: 1 3098 1 
-- userid: 1 result: 1 508 1 
-- userid: 1 result: 1 889 1 
-- userid: 1 result: 1 802 0 
-- userid: 1 result: 1 3800 0 

这里的问题开始。因为我希望我的用户ID加到了价值1。我的用户ID将是2循环将再次启动,并打印出像:

-- user id 2 result: ... 
-- user id 2 result: ... 
-- user id 2 result: ... 

但我的代码没有做到这一点。有人知道为什么

请注意:userid 2在我的TSV文件中,所以这不是问题!


额外的信息:在我的TSV文件我有以下情况:

1 802  0 
1 3800 0 
2 7492 1 
2 5235 0 

我要输出所有属于userid1(802,3800等)的结果,在那之后循环必须继续输出userid2的所有结果(7492,5235等)。在后面的过程中,我想为每个用户ID存储他们的结果。

回答

2

你的代码不超过1的userid进展Rob's answer解释原因。

在我看来,你的意图是打印用户ID 1的所有行,然后用户ID 2的所有行,依此类推。并且外部循环的范围表明您希望显示用户ID为1到9的行。

但是,一个问题是,一旦来自CSV文件的所有行都消耗完毕,for columns in tsvreader循环将不再有任何要迭代的内容过了,所以它的身体不会执行。没有进一步显示。这可以通过使用seek()“倒带”输入文件来克服。

修复这些错误导致这个代码:

import csv 

with open("source/to/file.tsv") as tsvfile: 
    tsvreader = csv.reader(tsvfile, delimiter="\t") 
    for userid in range(1,10): 
     tsvfile.seek(0) # back to the start of the CSV file 
     for columns in tsvreader: 
      column1, column2, column3 = columns 
      if userid == int(column1): 
       print("userid:", userid,"result: ", int(column1), int(column2), int(column3)) 

认为这是你所追求的。例如在输入(我用逗号作为分隔符):

 
2,4,4 
1,2,3 
1,4,5 
2,8,8 
1,6,7 
2,2,2 
4,1,1 
8,1,2 
10,4,0 
1,0,1 
4,4,4 
3,3,3 

输出将是:

 
userid: 1 result: 1 2 3 
userid: 1 result: 1 4 5 
userid: 1 result: 1 6 7 
userid: 1 result: 1 0 1 
userid: 2 result: 2 4 4 
userid: 2 result: 2 8 8 
userid: 2 result: 2 2 2 
userid: 3 result: 3 3 3 
userid: 4 result: 4 1 1 
userid: 4 result: 4 4 4 
userid: 8 result: 8 1 2 

注意,对于用户ID 10中的数据不包括作为该范围之外的userids。

我不得不猜测你的意图,但是,如果我是正确的,你想要做的是按用户ID分组数据,并按排序顺序显示。更好的方法是简单地在一个去所有的数据进行排序:

import csv 

with open("source/to/file.tsv") as tsvfile: 
    data = sorted(list(csv.reader(tsvfile, delimiter='\t')), 
        key=lambda row: int(row[0])) 
    for column1, column2, column3 in data: 
     print("userid:", column1, "result: ", int(column1), int(column2), int(column3)) 

输出:

 
userid: 1 result: 1 2 3 
userid: 1 result: 1 4 5 
userid: 1 result: 1 6 7 
userid: 1 result: 1 0 1 
userid: 2 result: 2 4 4 
userid: 2 result: 2 8 8 
userid: 2 result: 2 2 2 
userid: 3 result: 3 3 3 
userid: 4 result: 4 1 1 
userid: 4 result: 4 4 4 
userid: 8 result: 8 1 2 
userid: 10 result: 11 4 0 

如果你真的要排除一个给定的范围之外的用户ID,这样做:

import csv 

with open("source/to/file.tsv") as tsvfile: 
    data = sorted(list(csv.reader(tsvfile, delimiter='\t')), 
        key=lambda row: int(row[0])) 
    userids = range(1,10) 
    for column1, column2, column3 in data: 
     if int(column1) in userids: 
      print("userid:", column1, "result: ", int(column1), int(column2), int(column3)) 
+0

太棒了!这正是我想要的,解释非常有帮助!非常感谢! – Rotan075

+0

你也可以告诉我我应该如何输出每个user_id到一个单独的csv/tsv文件?或者那是不可能的@mhawke – Rotan075

+0

当然,这是可能的。在遍历排序的数据时,会跟踪当前用户标识。打开一个CSV文件并开始向其写入每一行。当用户标识更改时打开一个新的CSV文件并写入该文件。使用带有用户ID的字典作为键可以帮助将列表中每个用户的数据分组。然后迭代将每个数据写入文件的字典的键。 Burhan Khalid的[答案](http:// stackoverflow。com/a/31538379/21945)使用defaultdict为每个用户分组数据 - 您可以将您的代码关闭。 – mhawke

2

该代码重置每行的用户标识符(即在for columns in...循环内)。如果你在该循环之外移动那条线,我相信它会做你想做的。

+0

是的,它会加起来。但问题在于只输出:1 userid1的结果和1的userid2的结果,我想输出userid1的所有结果和userid2的所有结果等;) – Rotan075

+0

啊,我看到 - [mhawke的回答](http ://stackoverflow.com/a/31538708/215009)以上涵盖了这一点。 –

1

我不明白你尝试做什么,罗布海牙说你保持userid至1 ...

胡乱猜测你想要什么:

userid = 1 
tsv = csv.reader(open(filename), delimiter='\t') 
for i, row in enumerate(tsv): 
    if i > 10: 
     break 
    if str(userid) == row[0]: 
     print 'userid: %d result: %s' % (userid, row) 
     userid+= 1 
    else: 
     print 'not found: %s' % (row,) 

编辑

简单的方法(我不使用示例中的csv模块,因为您似乎不需要它),但使用更多的内存。

# load all data 
import collections 

data = collections.defaultdict(list) 

for line in open(filename): 
     row = line.strip().split('\t') 
     data[int(row[0])]+= [row[1:]] 

# output data grouped by user 
for userid, row in data.iteritems(): 
     print 'userid: %d result: %s' % (userid, row) 

另一个简单的方法(假设数据是排序由用户ID),尽快使用稍少存储器outputing结果。

def show(userid, row): 
    print 'userid: %s result: %s' % (userid, row) 

current = '' 
data = [] 
for line in open(filename): 
    row = line.strip().split('\t') 
    if row[0] != current: 
     if data: 
      show(current, data) 
      del data[:] 
     current = row[0] 
    data+=[row] 

show(row[0], data) 

如果数据未排序,你有记忆的问题,你可以存储在字典中的位置,并通过seek它(见file objects文档)。

+0

我为我的问题添加了一些额外的信息。也许你现在明白了吧) – Rotan075

+0

哦,你想通过文件寻找...我会编辑我的文章。 – bufh

+0

谢谢!这确实对我有用! :) – Rotan075

0
1 802  0 
1 3800 0 
2 7492 1 
2 5235 0 

我要输出所有属于该结果userid1(802,3800 等),其后的循环必须继续输出所有 userid2(7492,5235等)的结果。在后面的过程中,我想为每个 用户ID存储他们的结果。

您可以轻松地完成你正在尝试使用字典来实现的:

import csv 
from collections import defaultdict 

results_by_id = defaultdict(list) 

with open('somefile.csv') as f: 
    reader = csv.reader(f, delimiter='\t') 
    for row in reader: 
     results_by_id[row[0]].append(list(map(int, row[1:]))) 

for userid, results in results_by_id.iteritems(): 
    print('{} has {} total results'.format(userid, len(results))) 
    for result in results: 
     print('\t {}'.format(result)) 
+0

你能解释这是如何工作的吗?如何设置用户ID? – Rotan075