我知道这很简单,但我是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很愚蠢。
我应该补充说我的实际数据有小数而不是整数。我编辑了上面的数据来反映这一点。
答案 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 expression,file 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)
完全相同。)