Python 数据结构:按值排序的前K个字典键

Python 数据结构:按值排序的前K个字典键,python,dictionary,data-structures,heap,Python,Dictionary,Data Structures,Heap,我有一个非常大的字典,里面有{(元组):[int,int]}形式的条目。例如,dict={(1.0,2.1):[2,3],(2.0,3.1):[1,4],…}无法放入内存 我只对这个字典中的前K个值感兴趣,这些值按每个键的值中的第一个元素排序。如果有一个数据结构允许我只保留最大的K个键值对?例如,我的字典中只需要3个值。我可以输入以下键值对(1.0,2.1):[2,3],(2.0,3.1):[1,4],(3.1,4.2):[8,0],(4.3,4.1):[1,1]我的字典将是:(3.1,4.2)

我有一个非常大的字典,里面有
{(元组):[int,int]}
形式的条目。例如,
dict={(1.0,2.1):[2,3],(2.0,3.1):[1,4],…}
无法放入内存


我只对这个字典中的前K个值感兴趣,这些值按每个键的值中的第一个元素排序。如果有一个数据结构允许我只保留最大的K个键值对?例如,我的字典中只需要3个值。我可以输入以下键值对<代码>(1.0,2.1):[2,3],(2.0,3.1):[1,4],(3.1,4.2):[8,0],(4.3,4.1):[1,1]我的字典将是:
(3.1,4.2):[8,0],(1.0,2.1):[2.0,3.1],[1,4]
(如果键值对与第一个元素相同,将检查第二个元素,并保留基于第二个元素的最大键值对)

如果您的数据无法存储在内存中,您需要特别注意数据的存储方式。它是在数据库、平面文件、csv文件、JSON还是什么文件中

如果它是一个“矩形”文件格式,您可以简单地使用一个标准的*nix排序实用程序,然后只读取第一行
k

import heapq


class OnlyKDict(object):

    def __init__(self,K,key=lambda x:x):
        self.data = []
        self.dictionary = {}
        self.key=key         # Lambda function for the comparator
        self.K = K           # How many values to keep in dictionary

    def push(self,item):
        heapq.heappush(self.data,(self.key(item),item))
        self.dictionary[item[0]]=item[1]
        if len(self.data)>self.K:  #Size greater than k? pop minimum from heap and dict.
            item = self.pop()     #This ensure only k largest are there.
            self.dictionary.pop(item[0],None)

    def pop(self):
        return heapq.heappop(self.data)[1]

    def __getitem__(self,key):
        return self.dictionary[key]

    def __setitem__(self,key,value):
        if self.dictionary.has_key(key):
            self.dictionary[key] = value #If key present update value
        else:
            self.push((key,value))  ##Else push key and value as a tuple

h = OnlyKDict(8,lambda x:x[0][1] if x[0][1]==x[0][0] else x[0][0]) ##Compare 2nd value if both equal else compare 1st value only.

for i in xrange(10):
    h[(i,i)] = [i,i]

print h.dictionary
输出:{(5,5):[5,5],(6,6):[6,6],(4,4):[4,4],(7,7], (9,9):[9,9],(8,8],[2,2],[3,3]}

您可以看到这里仅存储了前8个值

主要的东西都是从我这里拿走的

我们要做的是创建我们的自定义堆类,它接受一个关键参数,在这里我们指定要排序的值


下一个是当这个尺寸大于8时,我们弹出最小项目。这确保了我们始终只有最多8个值。

这是一个定制的OrderedICT,为您保留N个最大的密钥:

from collections import OrderedDict
from operator import itemgetter


class LimitedSizeOrderedDict(OrderedDict):
    def __init__(self, *args, **kwds):
        self.maxlen = kwds.pop("maxlen", None)
        if args:
            try:
                top_n = sorted(*args, key=itemgetter(0, 0))[-self.maxlen:]
                self.min_key = top_n[0][0]
            except TypeError:
                raise Exception("keys should be in tuple format")
        else:
            self.min_key = (float("inf"), 0)
        super(LimitedSizeOrderedDict, self).__init__(top_n, **kwds)

    def __setitem__(self, key, value):
        if self._check_size():
            OrderedDict.__setitem__(self, key, value)
            if key[0] < self.min_key[0]:
                self.min_key = key
        elif key[0] > self.min_key[0]:
            self.pop(self.min_key)
            OrderedDict.__setitem__(self, key, value)
            self.min_key = min(self, key=itemgetter(0))

    def _check_size(self):
        if self.maxlen is not None:
            if len(self) < self.maxlen:
                return True
            return False
        return True

你是如何创建这本词典的?您想在创建词典时或创建词典后执行此操作?如果您不反对使用
numpy
它有
partition
argpartition
,可以在O(n)中找到顶部或底部的k。抱歉,我应该解释一下,我无法将字典保存在内存中。您只需要键和数组比dicts更高效。@Kasramvd:我想在创建时这样做。为什么不使用
key=…
?不,我们只保留8个值,因为这是必需的。。接下来,他还想归还一本词典。这就是为什么make_dict功能不只是因为他不能将所有的键都存储在内存中。。这就是为什么只有前8名。。他在评论中提到,我猜,
nlargest
的目的正是获取一个(可能很大的,想想文件)iterable并找到n个最大的项。创建结果的目录应该很简单。您能详细说明一下大的吗?在我看来,字典必须完全存储在内存中,然后调用
nlargest
top\n=sorted(args,itemgetter(0))[:self.maxlen]
是否意味着我必须读取所有数据?@Black No,如果您在创建词典时已将任何项传递给词典,则它将在初始化时返回前N项。@Black签出更新以获得更全面的答案。
In [2]: a = LimitedSizeOrderedDict([((7,2),3), ((2, 5), 3), ((6, 0), 1)], maxlen= 2)

In [3]: a
Out[3]: LimitedSizeOrderedDict([((6, 0), 1), ((7, 2), 3)])

In [4]: a[(12, 5)] = 10

In [5]: a
Out[5]: LimitedSizeOrderedDict([((7, 2), 3), ((12, 5), 10)])

In [6]: a[(10, 5)] = 9

In [7]: a
Out[7]: LimitedSizeOrderedDict([((12, 5), 10), ((10, 5), 9)])

In [8]: a[(0, 5)] = 9

In [9]: a
Out[9]: LimitedSizeOrderedDict([((12, 5), 10), ((10, 5), 9)])