Python - 为每个给定文件的密钥创建字典

时间:2011-12-14 07:17:39

标签: python file dictionary

我正在研究文本解析算法(开源方项目)。对于任何建议,我都非常感激。

我有一个制表符分隔的txt文件,该文件按第一列(下面的示例数据集)排序。此列中存在重复条目。 最后,我想使用散列指向所有具有相同键(第一列值)的值。如果出现新密钥,则将对哈希的内容进行序列化,保存等,然后清除该密钥以填充它。因此,我的目标是只有一把钥匙出现。因此,如果我有N个唯一键,我希望N个哈希值分别指向它们各自的条目。数据集虽然是GB的大小和内存堆不会有太大的帮助,因此我的理由是为每个密钥创建一个哈希并逐个处理。

样本数据集

A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123
...

所以在上面的数据集片段中,我希望有一个'A'的哈希值(指向它的3个相应项目)。读取“B”时,序列化“A”哈希并清除哈希内容。重复“B”直到数据集结束。

我的伪代码如下:

declare hash
for item in the dataset:
    key, value = item[0], item[1:]
    if key not in hash:
        if hash.size is 0: // pertains to the very first item
            hash.put(key, value)
        else:
            clear hash // if a new key is read but a diff. key is present. 
    else:
        hash.put(key, value) // key already there so append it.

如果对如何有效实施上述算法存在任何建议,我将非常感激。此外,如果我的哈希推理/方法效率不高或者可以提出改进,我会非常感激。我的目标是最终创建内存中的哈希,直到出现新密钥。

谢谢,

3 个答案:

答案 0 :(得分:1)

使用itertools.groupby,将文件作为迭代器传递:

from itertools import groupby
from cStringIO import StringIO

sourcedata = StringIO("""\
A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123""")

# or sourcedata = open("zillion_gigabyte_file.dat")

for key,lines in groupby(sourcedata, key=lambda s:s.split()[0]):
    accum = [float(s.split()[2]) for s in lines]
    print key, accum

groupby非常智能和高效,一次只在内存中保存很少的数据,在最后一刻之前保持纯粹的迭代器形式。你所描述的哈希并且一次只保留一个内存中的所有内容,而且已经在groupby中为你完成了。

答案 1 :(得分:0)

您可以为第一列中的每个键打开anydbm(2.x)或dbm(3.x),并以列的值命名。这非常简单 - 我不确定问题是什么。

你也可以使用像我的cachedb模块这样的东西,让它弄清楚某些东西是否是“新的”:http://stromberg.dnsalias.org/~strombrg/cachedb.html我在两个项目中都使用过它,两者都有很好的效果。

无论哪种方式,你都可以使你的密钥只是由换行符或空值或其他东西分隔的ascii浮点数列表。

答案 2 :(得分:0)

您没有明确说明您提供的排序数据是否典型,或者相同的密钥是否可以在整个文件中穿插其他密钥,这确实对算法产生了根本性的影响。我从您的示例代码中推断出它们将以任意顺序出现。

您也没有说您打算如何提取数据。这可能很重要 - 存储数据有许多不同的方法,应用程序可以是确定访问时间的关键功能。因此,您可能需要考虑使用各种不同的存储类型。如果您不知道如何使用最终结构,则以下建议可能不合适。

由于数据是浮点数,因此您可能需要考虑使用the shelve module来维护简化的字符串再次键入的浮点数列表。这具有以下优点:自动处理与外部存储器的所有酸洗和去除液体。如果您需要提高速度,请考虑使用更有效的酸洗协议(shelve.open()未使用的参数之一)。

# Transform the data:
# note it's actually more efficient to process line-by-line
# as you read it from a file - obviously it's best to try
# to avoid reading the whole data set into memory at once.
data = """\
A    ...    23.4421
A    ...   -23.442
A    ...    76.2224
B    ...    32.1232
B    ...    -23.001
C    ...    652.123"""

data = [(k, float(v))
          for (k, _, v) in
          [_.split() for _ in data.splitlines()]]

# create a shelve
import shelve
shelf = shelve.open("myshelf", "c")

# process data
for (k, v) in data:
    if k in shelf:
        # see note below for rationale
        tmp = shelf[k]
        tmp.append(v)
        shelf[k] = tmp
    else:
        shelf[k] = [v]

# verify results
for k in shelf.keys():
    print k, shelf[k]

您可能想知道为什么我不会在已经看到密钥的情况下使用shelf[k].append(v)。这是因为只有键分配的操作才会触发检测值的变化。您可以阅读搁置模块文档以获取更多详细信息,并了解如何使用二进制pickle格式。

另请注意,由于shelve.open()的“c”参数,此程序每次运行时都会重新创建工具架。