【问题标题】:How to split the file content by space and end-of-line character?如何按空格和行尾字符分割文件内容?
【发布时间】:2009-11-12 17:46:19
【问题描述】:

当我执行以下列表理解时,我会得到嵌套列表:

channel_values = [x for x in [ y.split(' ') for y in
    open(channel_output_file).readlines() ] if x and not x == '\n']

基本上我有一个由这个组成的文件:

7656 7653 7649 7646 7643 7640 7637 7634 7631 7627 7624 7621 7618 7615
8626 8623 8620 8617 8614 8610 8607 8604 8600 8597 8594 8597 8594 4444
<snip several thousand lines>

此文件的每一行都以新行结束。

基本上我需要将每个数字(它们都用一个空格分隔)添加到一个列表中。

有没有更好的方法通过列表理解来做到这一点?

【问题讨论】:

    标签: python list-comprehension


    【解决方案1】:

    您不需要列表推导:

    channel_values = open(channel_output_file).read().split()
    

    【讨论】:

    • 完全杀死它(y)
    【解决方案2】:

    这样做:

    channel_values = open(channel_output_file).read().split()
    

    split() 将根据包含' ' '\t' and '\n' 的空格进行拆分。它会将所有值拆分为一个列表。

    如果你想要整数值,你可以这样做:

    channel_values = map(int, open(channel_output_file).read().split())
    

    或使用列表推导:

    channel_values = [int(x) for x in open(channel_output_file).read().split()]
    

    【讨论】:

      【解决方案3】:

      此外,原始列表解析具有嵌套列表的原因是因为您使用内部方括号集添加了额外级别的列表解析。你的意思是:

      channel_values = [x for x in y.split(' ') for y in
          open(channel_output_file) if x and not x == '\n']
      

      其他答案仍然是编写代码的更好方法,但这就是问题的原因。

      【讨论】:

      • 你有这个open(channel_output_file).readlines(),但你真正需要的是open(channel_output_file)open() 返回的文件对象用作返回行的迭代器; readlines() 将在每一行中啜饮,这里不需要。我已编辑您的代码以删除“readlines()”。还投票给你 +1。
      • 这将失败,因为您混淆了“for x in ...”和“for y in ...”的顺序。 Python 的嵌套列表理解语法是违反直觉的,除非你记得它模仿了你在没有理解的情况下纠正你的 for 循环的顺序。另外,为什么不直接 split() 并跳过换行符的测试?
      • (希望这条评论不会出现不止一次 - 如果出现了道歉)关于 x 和 y 的顺序的观点,谢谢!这很令人困惑。我留在 split() 以及 Steve 删除的 readlines() 的原因是通过对原始代码进行尽可能小的更改来显示导致嵌套列表问题的原因。 Lukáš 和 Nadia 已经展示了如何使代码变得更好。
      【解决方案4】:

      如果您不关心悬空文件引用,并且您确实必须一次将一个列表全部读入内存,那么其他答案中提到的单线确实有效:

      channel_values = open(channel_output_path).read().split()
      

      在生产代码中,我可能会使用生成器,如果不需要它们,为什么要阅读所有这些行?

      def generate_values_for_filename(filename):
          with open(filename) as f:
              for line in f:
                  for value in line.split():
                      yield value
      

      如果你真的需要做一些除了迭代值之外的事情,你可以在以后创建一个列表:

      channel_values = list(generate_values_for_filename(channel_output_path))
      

      【讨论】:

        【解决方案5】:

        另外一个问题是您让文件处于打开状态。请注意,openfile 的别名。

        试试这个:

        f = file(channel_output_file)
        channel_values = f.read().split()
        f.close()
        

        请注意,它们将是字符串值,因此如果您想要整数值,请将第二行更改为

        channel_values = [int(x) for x in f.read().split()]
        

        如果文件中有非整数值,int(x) 将抛出 ValueError

        【讨论】:

        • 我认为一旦您离开列表理解范围,文件就会自动关闭?
        • 文件对象在被垃圾回收时关闭,在没有引用时被垃圾回收。所以不,它不会让文件保持打开状态,因为在该行执行后没有对它的引用。
        • 谢谢,我有点担心 :)
        【解决方案6】:

        有没有更好的方法通过列表理解来做到这一点?

        有点..

        使用.readlines() 方法,您可以使用.read(),而不是将每一行作为数组读取:

        channel_values = [x for x in open(channel_output_file).readlines().split(' ')
        if x not in [' ', '\n']]
        

        如果您需要做更复杂的事情,尤其是涉及多个列表理解时,您最好将其扩展为常规的 for 循环。

        out = []
        for y in open(channel_output_file).readlines():
            for x in y.split(' '):
                if x not in [' ', '\n']:
                    out.append(x)
        

        或者使用 for 循环和列表理解:

        out = []
        for y in open(channel_output_file).readlines():
            out.extend(
                [x for x in y.split(' ')
                if x != ' ' and x != '\n'])
        

        基本上,如果您不能简单地使用列表解析(或需要嵌套它们)来做某事,那么列表解析可能不是最佳解决方案。

        【讨论】:

          猜你喜欢
          • 2011-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-11
          • 2021-10-05
          • 1970-01-01
          • 1970-01-01
          • 2018-03-22
          相关资源
          最近更新 更多