使用Python在一列中选择具有特定值范围的行

时间:2012-04-27 21:53:59

标签: python parsing loops rows

我知道这很简单,但我是Python的新用户,所以我在这里遇到了一些麻烦。我顺便使用Python 3。

我有多个看起来像这样的文件:

NAME DATE AGE SEX COLOR

Name Date Age Sex Color
Ray  May  25.1 M  Gray
Alex Apr  22.3 F  Green
Ann  Jun  15.7 F  Blue

(假设这是制表符分隔。我应该补充一点,真正的文件将有大约3,000行和17-18列)

我想要做的是选择年龄列中小于23的值的所有行。

在此示例中,输出为:

Name Date Age Sex Color
Alex Apr  22.3 F  Green
Ann  Jun  15.7 F  Blue

这是我试图做的事情:

f = open("addressbook1.txt",'r')
line = f.readlines()
file_data =[line.split("\t")]
f.close()

for name, date, age, sex, color in file_data:
    if age in line_data < 23:
        g = open("college_age.txt",'a')
        g.write(line)
    else:
        h = open("adult_age.txt",'a')
        h.write(line)

现在,理想情况下,我有20-30个这样的“地址簿”输入文件,我希望这个脚本循环遍历它们,并将年龄低于23的所有条目添加到同一输出文件(“college_age.txt”) 。我真的不需要保留其他线路,但我不知道还能用它们做什么。

此脚本在运行时会生成错误。

AttributeError: 'list' object has no attribute 'split'

然后我将第三行更改为:

file_data=[line.split("\t") for line in f.readlines()]

它不再给我一个错误,但根本什么都不做。它刚刚开始然后开始。

有任何帮助吗? :)记住我对Python很愚蠢。

我应该补充说我的实际数据有小数而不是整数。我编辑了上面的数据来反映这一点。

3 个答案:

答案 0 :(得分:5)

这里的问题是您使用readlines()两次,这意味着第一次读取数据,第二次没有任何内容。

您可以直接在文件上进行迭代而不使用readlines() - 事实上,这是更好的方法,因为它不会立即读取整个文件。

虽然您可以使用str.split()来执行您要执行的操作,但更好的选择是使用专为此任务设计的the csv module

import csv

with open("addressbook1.txt") as input, open("college_age.txt", "w") as college, open("adult_age.txt", "w") as adult:
   reader = csv.DictReader(input, dialect="excel-tab")
   fieldnames = reader.fieldnames
   writer_college = csv.DictWriter(college, fieldnames, dialect="excel-tab")
   writer_adult = csv.DictWriter(adult, fieldnames, dialect="excel-tab")
   writer_college.writeheader()
   writer_adult.writeheader()
   for row in reader:
       if int(row["Age"]) < 23:
          writer_college.writerow(row)
       else:
          writer_adult.writerow(row)

那我们在这做什么?首先,我们使用the with statement作为opening files。它不仅具有更多的pythonic和可读性,而且可以处理关闭,即使发生异常也是如此。

接下来,我们创建一个DictReader,它将文件中的行作为字典读取,自动使用第一行作为字段名称。然后我们让编写者回写我们的拆分文件,然后编写标题。使用DictReader是一个优先选择的问题。它通常用于您经常访问数据的地方(当您不知道列的顺序时),但它使代码在这里可读性很好。但是,您可以使用标准csv.reader()

接下来,我们循环遍历文件中的行,检查age(我们将其转换为int,以便我们可以进行数值比较)以了解要写入的文件。 with语句会为我们关闭文件。

对于多个输入文件:

import csv

fieldnames = ["Name", "Date", "Age", "Sex", "Color"]
filenames = ["addressbook1.txt", "addressbook2.txt", ...]

with open("college_age.txt", "w") as college, open("adult_age.txt", "w") as adult:
   writer_college = csv.DictWriter(college, fieldnames, dialect="excel-tab")
   writer_adult = csv.DictWriter(adult, fieldnames, dialect="excel-tab")
   writer_college.writeheader()
   writer_adult.writeheader()
   for filename in filenames:
       with open(filename, "r") as input:
           reader = csv.DictReader(input, dialect="excel-tab")
           for row in reader:
               if int(row["Age"]) < 23:
                  writer_college.writerow(row)
               else:
                  writer_adult.writerow(row)

我们只是添加一个循环来处理多个文件。请注意,我还添加了一个字段名称列表。在我刚刚使用文件中的字段和顺序之前,但由于我们有多个文件,我认为这样做更明智。另一种方法是使用第一个文件来获取字段名称。

答案 1 :(得分:0)

我认为最好使用csv模块来阅读这些文件http://docs.python.org/library/csv.html

答案 2 :(得分:-3)

ITYM

with open("addressbook1.txt", 'r') as f:
    # with automatically closes
    file_data = ((line, line.split("\t")) for line in f)
    with open("college_age.txt", 'w') as g, open("adult_age.txt", 'w') as h:
        for line, (name, date, age, sex, color) in file_data:
            if int(age) < 23: # float() if it is not an integer...
                g.write(line)
            else:
                h.write(line)

看起来文件数据可能会多次迭代。但是感谢generator expressionfile data只是一个生成器,如果被要求这样做,会分发文件的下一行。它被要求在for循环中这样做。这意味着,for循环检索的每个项都来自生成器file_data,根据请求,每个文件行都会转换为一个元组,其中包含完整的行(用于复制)及其组件(用于测试)。

另一种选择可能是

file_data = ((line, line.split("\t")) for line in iter(f.readline, ''))
  • 它比迭代文件更接近readlines()。由于readline()在幕后的行为与文件的迭代略有不同,因此可能需要这样做。

(如果你不喜欢函数式编程,你也可以手动调用readline()创建一个生成器函数,直到返回一个空字符串。

如果您根本不喜欢嵌套生成器,则可以执行

with open("addressbook1.txt", 'r') as f, open("college_age.txt", 'w') as g, open("adult_age.txt", 'w') as h:
    for line in f:
        name, date, age, sex, color = line.split("\t")
        if int(age) < 23: # float() if it is not an integer...
            g.write(line)
        else:
            h.write(line)

完全相同。)