Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python中字典列表的字典中的最大值_Python_Algorithm_List_Dictionary - Fatal编程技术网

Python中字典列表的字典中的最大值

Python中字典列表的字典中的最大值,python,algorithm,list,dictionary,Python,Algorithm,List,Dictionary,考虑字典列表的字典,例如: {1: [{'date': 6/31/2015, 'bits': 1}, {'date': 6/25/2015, 'bits': 5}], 2: [{'date': 7/31/2013, 'bits': 5}, {'date': 7/28/2015, 'bits': 0}], 6: [{'date': 4/23/2010, 'bits': 10}, {'date': 1/1/2009, 'bits': 1}]} 从时间复杂度的角度

考虑字典列表的字典,例如:

{1: [{'date': 6/31/2015, 'bits': 1},
     {'date': 6/25/2015, 'bits': 5}],
 2: [{'date': 7/31/2013, 'bits': 5},
     {'date': 7/28/2015, 'bits': 0}],
 6: [{'date': 4/23/2010, 'bits': 10},
     {'date': 1/1/2009,  'bits': 1}]}
从时间复杂度的角度来看,从主字典中按键分组的内部字典中查找键的最大值的条目最有效的方法是什么?在平局的情况下,最内层字典中的另一个键决定胜负

使用上面的字典,查找键
'bits'
的最大值,使用键
'date'
打破联系(偏向最近的),结果应该是字典

{1: {'date': 6/25/2015, 'bits': 5},
 2: {'date': 7/31/2013, 'bits': 5},
 6: {'date': 4/23/2010, 'bits': 10}}`.
#callable that returns subscriptable['bits']
bits = operator.itemgetter('bits')
我目前有一个使用两个嵌套的
for
循环的实现。我正在考虑按字段
位对列表进行排序,以找到值最大的条目

当前的实现如下所示:

for key in dicts:
   for data in dicts[key]:
      if(data["bits"]>max_bits):
         max_bits= data["bits"]
         date =data["date"]
      elif (data["bits_corrected"]==max_bits):
           if(data["date"] >date):
              date=data["date"]
但是,对于大型数据集来说,这需要花费大量的时间。请建议最佳解决方案

以下是想法:


这有用吗


如果您不喜欢此解决方案,请告诉我,我将删除它。

在我对其进行了一点研究之后,我认为您无法绕过嵌套循环或多次迭代。如果您必须考虑关系,则需要迭代内部字典,最坏的情况是,您必须迭代所有这些项以打破关系-因此复杂性保持不变


尽量利用内置的和,,(都是标准库的一部分)。即使时间复杂度相同,它们也可以加快速度

我们需要编写一个可以与
max
一起使用的键函数


虽然以下内容可能具有指导意义,但它会根据
键断开连接。它使用一个键函数,从
数据
的每个项目的每个内部字典返回排序后的
值。确保看到底部的编辑

我还使用了一个方便的函数,可以将多个函数串在一起。我把它放在工具箱里,它没有属性,所以我不知道是我写的还是在什么地方找到的——我可能找到了

import functools, operator
def compose(funcs):
    '''Return a callable composed of successive application of functions

    funcs is an iterable producing callables
    for [f, g, h] returns f(g(h(*args, **kwargs)))

    >>> def f(x):
            return int(x ** .5)

    >>> def g(x):
            return x*x

    >>> def h(x):
            return -x

    >>> foo = compose([f, g, h])
    >>> foo(2)
    2
    >>>
    '''
    def outer(f, g):
        def inner(*args, **kwargs):
            return f(g(*args, **kwargs))
        return inner
    return functools.reduce(outer, funcs)
我们需要
数据中每个(k,v)项的值

#callable that returns sequence[1]
item1 = operator.itemgetter(1)
我们需要一个something来获取内部字典的

{1: {'date': 6/25/2015, 'bits': 5},
 2: {'date': 7/31/2013, 'bits': 5},
 6: {'date': 4/23/2010, 'bits': 10}}`.
#callable that returns subscriptable['bits']
bits = operator.itemgetter('bits')
我们需要迭代每个内部字典并提取

#callable that will map the callable bits to a sequence
#this becomes an inner nested loop
get_bits = functools.partial(map, bits)
我们需要反向排序

reverse_sort = functools.partial(sorted, reverse = True)
编写一个键函数,返回您感兴趣的内容

funcs = [reverse_sort, get_bits, item1]
key = compose(funcs)
# key is now equivalent to sorted(get_bits(item1(item)), reverse = True)

>>> # iterate over data.items() and find the max
>>> print(max(data.items(), key = key))
(7, [{'date': '4/23/2010', 'bits': 2}, {'date': '1/1/2009', 'bits': 10}])
我不知道为什么我喜欢函数式,但你也可以这样写关键函数(我想,很多人会觉得这样更可读)


编辑

似乎我误读了或没有看到平局断路器是
date
字段。 这使它变得容易一点

#callable that returns a ('bits', 'date') tuple
bits_date = operator.itemgetter('bits', 'date')

def key3(item):
    '''return the best dictionary from an item
    '''
    one = item[1]
    # max is an inner loop when this is used as a key function
    return max(one, key = bits_date)
# or
item1 = operator.itemgetter(1)
best = functools.partial(max, key = bits_date)
key4 = compose([best, item1])

>>> # max in the next statement(s) is the outer loop
>>> print(max(d.items(), key = key3))
(6, [{'date': datetime.datetime(2010, 4, 23, 0, 0), 'bits': 10}, {'date': datetime.datetime(2009, 1, 2, 0, 0), 'bits': 1}])
>>> print(max(d.items(), key = key4))
(6, [{'date': datetime.datetime(2010, 4, 23, 0, 0), 'bits': 10}, {'date': datetime.datetime(2009, 1, 2, 0, 0), 'bits': 1}])
>>>

让我们做一个框架,从经验上回答这个问题。最好是测试算法的实际运行速度,而不仅仅是猜测

首先是生成测试数据的方法:

import datetime
import random

def generate_data(sz_outer, sz_inner):
    res = {}
    for n in range(sz_outer):
        res[n] = []
        for m in range(sz_inner):
            date = datetime.date(
                year=random.sample(range(2010, 2015), 1)[0],
                month=random.sample(range(1, 13), 1)[0],
                day=random.sample(range(1, 29), 1)[0],
                )
            bits = random.sample(range(10), 1)[0]
            res[n].append({'date': date, 'bits': bits})
    return res
这里有两种可能的解决方案。第一种方法使用
pandas
模块将词典列表转换为更结构化的数据类型。第二个是使用纯Python的简单实现,以及基于键的元组(按重要性排序)的排序键

def choose_best1(dict_list):
    df = pandas.DataFrame.from_records(dict_list)
    return df.sort(['bits', 'date']).irow(-1).to_dict()

def choose_best2(dict_list):
    srted = sorted(dict_list, key=lambda k: (k['bits'], k['date']))
    return srted[-1]
运行测试的方法:

def run_test(data, method=choose_best1):
    bests = {}
    for key, dict_list in data.items():
        best = method(dict_list)
        bests[key] = best
    return bests
无论采用哪种方法,我们都能得到相同的结果:

data = generate_data(10, 10000)
bests1 = run_test(data, choose_best1)
bests2 = run_test(data, choose_best2)
哪个更快?完全取决于最里面的字典列表的大小。对于足够大的内部列表,为了从pandas中提供的更优化的排序算法中获益,支付转换为DataFrame的前期成本是值得的。对于简短的内部列表,最好只使用
排序

使用10000条记录时,pandas方法速度更快:

data = generate_data(10, 10000)

In [79]: %timeit run_test(data, choose_best1)
10 loops, best of 3: 116 ms per loop

In [80]: %timeit run_test(data, choose_best2)
10 loops, best of 3: 151 ms per loop
对于100条记录,排序方法要快得多:

data = generate_data(10, 10000)

In [82]: %timeit run_test(data, choose_best1)
100 loops, best of 3: 15 ms per loop

In [84]: %timeit run_test(data, choose_best2)
1000 loops, best of 3: 710 µs per loop

请注意,外部字典的大小完全无关,因为每个条目都是完全独立处理的。因此,总时间只是外部字典中每个条目所需时间的总和。

是否处理打破平衡的情况(如果不同日期的位值相同)?如果您有一个有效的解决方案,您应该将其发布在您的答案中。你甚至可以考虑把它放进去,因为你有一个工作解决方案并要求批评/替代。至于时间复杂度,看来你需要迭代主字典并遍历主词典中每个项目的值——因此,嵌套循环可能是时间复杂性最好的方法。任何将进程下推到c中的策略都可能使其速度更快,但复杂度似乎保持不变。@wwii您的意思是嵌套for循环是我们在这种情况下可以实现的最佳解决方案?难道我们不能对内部字典进行排序,并获得位的最大值和相应的日期吗?是的,我说话时不假思索。排序列表比O(N)好,因此如果您可以将其中一个循环转换为排序,那么您将得到改进。对于
“日期”:6/31/2015
值的数据类型是什么
6/31/2015
?很好的解决方案,我有一个疑问,在这两种方法中,您都在排序日期和位,或者只排序位,日期将与相应的位一起显示?在这两种方法中,我们都将“位”和“日期”作为排序键传递。因此,它将首先按位排序,并使用日期来打破关系。它将返回保留位和日期字段的完整数据集。
data = generate_data(10, 10000)

In [82]: %timeit run_test(data, choose_best1)
100 loops, best of 3: 15 ms per loop

In [84]: %timeit run_test(data, choose_best2)
1000 loops, best of 3: 710 µs per loop