嵌套python列表理解以构造列表列表

嵌套python列表理解以构造列表列表,python,list-comprehension,Python,List Comprehension,我是python新手,在探索嵌套列表理解时遇到了困难。我试图编写一些代码来读取文件,并为每行的每个字符构造一个列表 因此,如果文件包含 xxxcd cdcdjkhjasld asdasdxasda 由此产生的清单将是: [ ['x'、'x'、'x'、'c'、'd'] [c','d','c','d','j','k','h','j','a','s','l','d'] [a'、's'、'd'、'a'、's'、'd'、'x'、'a'、's'、'd'、'a'] ] 我已经编写了下面的代码,它是可以工作的

我是python新手,在探索嵌套列表理解时遇到了困难。我试图编写一些代码来读取文件,并为每行的每个字符构造一个列表

因此,如果文件包含

xxxcd
cdcdjkhjasld
asdasdxasda
由此产生的清单将是:

[
['x'、'x'、'x'、'c'、'd']
[c','d','c','d','j','k','h','j','a','s','l','d']
[a'、's'、'd'、'a'、's'、'd'、'x'、'a'、's'、'd'、'a'] ]

我已经编写了下面的代码,它是可以工作的,但是我有一种烦人的感觉,我应该能够编写一个嵌套的列表来用更少的代码行完成这项工作。如有任何建议,将不胜感激

data = []
f = open(file,'r')
for line in f:
    line = line.strip().upper()
    list = []
    for c in line:
        list.append(c)
    data.append(list)

下面是列表理解的一个层次

data = []
f = open(file,'r')

for line in f:
    data.append([ch for ch in line.strip().upper()])
但我们可以一次完成全部工作:

f = open(file, 'rt')
data = [list(line.strip().upper()) for line in f]
这是使用
list()
将字符串转换为单个字符串的列表。我们还可以使用嵌套列表理解,并将
open()
内联:

data = [[ch for ch in line.strip().upper()] for line in open(file, 'rt')]
然而,在这一点上,我认为对列表的理解有损于正在发生的事情的易读性

对于复杂的处理,例如列表中的列表,您可能希望对外层使用
For
循环,对内层使用列表理解

此外,正如Chris Lutz在评论中所说,在这种情况下,确实没有理由明确地将每一行拆分为字符列表;您始终可以将字符串视为列表,可以将字符串方法与字符串一起使用,但不能将字符串方法与列表一起使用。(好的,您可以使用
'.join()
将列表重新连接回一个字符串,但为什么不将其保留为一个字符串?

这应该会有所帮助(您可能需要使用它来去除换行符或按需格式化,但基本想法应该可行):


首先,您可以将line.strip().upper()部分与外部for循环相结合,如下所示:

for line in [l.strip().upper() for l in f]:
    # do stuff
然后,您可以对字符进行迭代,形成一个列表理解,但不会更短或更清晰。你在那里做的最整洁的方式是:

list(someString)
因此,你可以:

data = [list(l.strip().upper()) for l in f]
我不知道它是否能很好地表达你的意图。错误处理也是一个问题,如果途中出现问题,整个表达式将失效


如果不需要将整个文件和所有行存储在内存中,可以将其转换为生成器表达式。这在处理大型文件时非常有用,并且一次只需要处理一个块。生成器表达式改用括号,如下所示:

data = (list(l.strip().upper()) for l in f)
数据
将成为一个生成器,为文件中的每一行运行表达式,但仅当您对其进行迭代时;将其与列表理解相比较,列表理解将在内存中创建一个巨大的列表。请注意,<代码>数据< /C> >不是一个列表,而是一个生成器,更多的是C++中的迭代器或C中的IEnumerator。


生成器可以很容易地输入到列表中:
list(someGenerator)
这在某种程度上会破坏目的,但有时是必要的。

在您的例子中,您可以使用
list
构造函数来处理内部循环,并使用列表理解来处理外部循环。比如:

>>> f = file('teste.txt')
>>> print map(lambda x: [c for c in x][:-1], f)
[['x', 'x', 'x', 'c', 'd'], ['c', 'd', 'c', 'd', 'j', 'k', 'h', 'j', 'a', 's', 'l', 'd'], ['a', 's', 'd', 'a', 's', 'd', 'x', 'a', 's', 'd']]
f = open(file)
data = [list(line.strip().upper()) for line in f]
给定一个字符串作为输入,列表构造函数将创建一个列表,其中字符串的每个字符都是列表中的单个元素

列表理解在功能上等同于:

data = []
for line in f:
    data.append(list(line.strip().upper()))

字符串和字符列表之间唯一真正重要的区别是字符串是不可变的。可以像遍历列表一样对字符串进行迭代和切片。将字符串作为字符串处理更方便,因为它们支持字符串方法,而列表不支持

因此,对于大多数应用程序,我不会费心将
数据中的项转换为列表;我只想:

data = [line.strip() for line in open(filename, 'r')]
当我需要将
data
中的字符串作为可变列表进行操作时,我会使用
list
转换它们,并使用
join
将它们放回原处,例如:

data[2] = ''.join(sorted(list(data[2])))

当然,如果您要对这些字符串进行的只是修改它们,那么请继续,将它们存储为列表。

对于简单性和可读性,还有很多要说的。虽然嵌套理解可能会获得相同的效果,但也可能会意外地导致某些内容混淆。此外,不要使用名为
file
的变量。我知道
file
open
是同义词,但是如果你需要测试,比如说,
isinstance(f,file)
你会后悔的。也许可以称之为
文件名
?名为
list
+1的变量也是如此,但我宁愿将列表中的每个条目都保留为字符串。因为字符串可以被索引,所以您仍然可以将其视为二维字符数组。只有当OP计划更改行时,
列表(…)
部分才是必需的。有人能解释一下这种形式的内部理解是如何工作的吗?我一直在努力解决这个问题。
data = [line.strip() for line in open(filename, 'r')]
data[2] = ''.join(sorted(list(data[2])))