【问题标题】:Count every character from file计算文件中的每个字符
【发布时间】:2013-01-05 21:07:15
【问题描述】:

我正在尝试计算文件中的每个字符并将其放入字典中。 但它不太好用,我没有得到所有字符。

#!/usr/bin/env python
import os,sys

def count_chars(p):
     indx = {}
     file = open(p)

     current = 0
     for ch in file.readlines():
          c = ch[current:current+1]
          if c in indx:
               indx[c] = indx[c]+1
          else:
               indx[c] = 1           
          current+=1
     print indx

if len(sys.argv) > 1:
     for e in sys.argv[1:]:
          print e, "contains:"
          count_chars(e)
else:
     print "[#] Usage: ./aufg2.py <filename>"

【问题讨论】:

    标签: python


    【解决方案1】:

    假设您计数的文件在内存中的大小合理:

    import collections
    with open(p) as f:
        indx = collections.Counter(f.read())
    

    否则,你可以一点一点地阅读:

    import collections
    with open(p) as f:
        indx = collections.Counter()
        buffer = f.read(1024)
        while buffer:
            indx.update(buffer)
            buffer = f.read(1024)
    

    【讨论】:

    • 或者让它更明确一点,让缓冲自然发生——比如Counter(iter(lambda: f.read(1), ''))
    • @JonClements 读取少量字节不是比从块中读取文件慢得多吗?
    • @ovgolovin 否...对于缓冲输入流,您只需读入缓冲区,然后自然溢出...
    • 一个轻率的想法是使用mmap,它会做所有的缓冲。但我没有对其进行任何研究,因此无法将其作为单独的答案。
    • @ovgolovin 它可以工作,但在这个用例中 - 不是最好的选择
    【解决方案2】:

    主要问题是您只检查(最多!)每一行中的一个字符。如果您正在逐行读取文件,则需要有一个内部循环来遍历该行的字符。

    #!/usr/bin/env python
    import os, sys, collections
    
    def count_chars(p):
         indx = collections.Counter()
         with open(p) as f:
             for line in f:
                 for c in line:
                     indx[c] += 1
         print indx
    
    if len(sys.argv) > 1:
         for e in sys.argv[1:]:
              print e, "contains:"
              count_chars(e)
    else:
         print "[#] Usage: ./aufg2.py <filename>"
    

    【讨论】:

      【解决方案3】:

      使用defaultdict。基本上,如果您尝试在 defaultdict 中获取不存在的项,它会创建键并调用构造函数指定的第 0 个参数作为值。

      import collections
      
      def count_chars(p):
          d = collections.defaultdict(int)
          for letter in open(p).read():
              d[letter] += 1
          return d
      

      【讨论】:

      • defaultdict 是错误的数据结构,因为Counter 存在于同一个模块中。
      【解决方案4】:

      我已将此作为对@Amber 答案的评论发布,但将在此处重复...

      计算文件中字节的出现次数,然后生成一个小的迭代器:

      with open('file') as fin:
          chars = iter(lambda: fin.read(1), '')
          counts = Counter(chars)
      

      这样,来自fin 的底层缓冲仍然适用,但它仍然更隐含的是您一次读取一个字节(而不是块大小,无论如何操作系统都会自行执行),它还允许不在Counter 对象上使用update,实际上它更像是一个完整的、独立的指令。

      【讨论】:

      • +1!但是可能有问题。因为按 1 个字节读取可能会很慢。我在回答这个问题时遇到了这个问题:stackoverflow.com/a/8284246/862380
      • @ovgolovin 很有趣-partial(fin.read, 1) 可能比 lambda 更适合函数调用开销,但除此之外,我认为没有理由使用缓冲,它会是任何比读取块慢(尽管不要争辩) - 也可以在open...上指定缓冲区大小...
      • 我不确定partial,因为它可能在读取每个字节时调用fin.read。我评论只是因为我不完全理解这些问题,我希望我能学到一些新东西!那个时候,我真的被分块读取和读取 1 个字节之间的 60 比率弄糊涂了。还有一件事,Python 中的这些基准是不稳定的,因为 Python 版本之间的变化使数据发生了巨大变化。
      • @ovgolovin 我得早起,所以恐怕是我晚上退休的时候了,但是是的,Py3 的第一个版本在文件 IO 方面的基准非常可怕,并且错误已得到修复在其他年份的缓冲和 IO 中,部分函数与 lambda 函数略有不同......那里有很多讨论......这本身就是一个问题!
      猜你喜欢
      • 1970-01-01
      • 2022-07-08
      • 2015-09-30
      • 2014-04-17
      • 2023-04-03
      • 1970-01-01
      • 2021-11-03
      • 2022-10-15
      • 1970-01-01
      相关资源
      最近更新 更多