Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.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_Sorting - Fatal编程技术网

Python 优化组合可变大小列表的算法

Python 优化组合可变大小列表的算法,python,algorithm,sorting,Python,Algorithm,Sorting,我创建了一个算法,将来自不同列表的数据合并到一个列表中。这个问题是关于设计这个算法的有效/优化版本 背景: 输入包括包含(值、提交时间)对的元组列表。这些可以看作是二维阵列。以下是输入示例: l1 = [(value-11, time-11),(value-12, time-12),(value-13, time-13),(value-14, time-14),(value-15, time-15)] l2 = [(value-21, time-21),(value-22, time-22)]

我创建了一个算法,将来自不同列表的数据合并到一个列表中。这个问题是关于设计这个算法的有效/优化版本

背景:

输入包括包含(值、提交时间)对的元组列表。这些可以看作是二维阵列。以下是输入示例:

l1 = [(value-11, time-11),(value-12, time-12),(value-13, time-13),(value-14, time-14),(value-15, time-15)]
l2 = [(value-21, time-21),(value-22, time-22)]
l3 = [(value-31, time-31),(value-32, time-32),(value-33, time-33),(value-34, time-34)]
l4 = [(value-41, time-41),(value-42, time-42),(value-43, time-43),(value-44, time-44),(value-45, time-45)]
l5 = [(value-51, time-51)]
.
.
.
ln = [(value-n1, time-n1),(value-n2, time-n2),....(value-nm, time-nm)]
请注意:

  • 列表的大小是可变的
  • 列表按提交时间排序
  • 最近的元组出现在最左边的位置
  • 每个元组中的时间是将所述元组提交到列表中的实际时间
  • 这些名单没有一一填写。即
    time-21
    不一定晚于
    time-15
要求:

我试图根据给定的输入生成一个组合列表。结果是包含从所有输入列表中获取的最新的
k
元组。现在让我们设置
k=20

当前方法:

我从每个列表中检索最多20个元素。我将它们组合成一个单数列表,按每个元组的提交时间排序。然后我从这个结果中选择前20个元素

不用说,这是一种相当残忍的方法。它的伸缩性不如列表的数量。我本以为我能做得更好,但到目前为止还没能想出什么办法。从专家那里得到一个关于如何尽可能有效地进行此类操作的示例将是非常好的

如果有关系的话,我个人的偏好是python



p、 我们可以使用一种黑客来回避这个问题。那就是一直保持一个综合的全球清单。出于这个问题的目的,让我们忽略这一点。

这里是一种有效的方法,使用它可以让您惰性地合并已排序的列表

(编辑:我刚刚意识到我误读了问题的一部分-最近的项目,所以时间较长的项目,在左边,在列表的开头,而不是像我想象的那样在末尾。所以,同样的事情,但我们甚至不必按相反的顺序重复列表):

我们将列表交给
merge
,它将惰性地对它们进行迭代,每次取
时间较大的元组

时间是每个元组中索引1处的值,因此
key=itemgetter(1)

merge
的默认行为是获取具有最小值的项,因此我们必须使用
reverse=True
告诉它选择最大值

然后,我们使用
islice
从中获取第一个(这里是5个)项目,并将其转换为一个列表

因此,由于所有内容都基于迭代器,因此仅从列表中检索必要的项


如果元组按照相反的顺序排序,正如我最初想象的那样,最新的元组位于列表的末尾:我们必须以相反的顺序在列表上迭代:

from heapq import merge
from itertools import islice
from operator import itemgetter

l1 = [("a1", 10),("b1", 20),("c1", 30),("d1", 40)]
l2 = [("a2", 9),("b2", 24),("c2", 32)]
l3 = [("a3", 16),("b3", 18),("c3", 35)]

data = [l1, l2, l3]

out = list(islice(merge(*map(reversed, data), key=itemgetter(1), reverse=True), 5))

print(out)
# [('d1', 40), ('c3', 35), ('c2', 32), ('c1', 30), ('b2', 24)]

为了回答您的最后一点意见,这里有一个解决方案适用于早于3.5的Python版本,在引入
反向
heapq.merge
的关键字参数之前

我们的想法仍然是使用迭代器和生成器表达式,以便每次访问和处理一个数据段。键不是一个大问题,但是替换
reverse
要复杂一些,因为
merge
希望它收到的列表按递增顺序排序

一个解决方案是通过添加第一个字段来修饰从列表中读取的每个元组,该字段的时间顺序将相反。因为我们不能使用“负时间”,所以我们可以使用timedelta
datetime.max-time
。 在返回元组之前,我们只需删除第一个字段

我创建了一个生成器,它在列表上迭代并生成修饰的元组。我将生成器表达式分隔开,以避免出现一行很长且难以阅读的行:

# Before Python 3.5, merge doesn't support key and reverse

from heapq import merge
from itertools import islice
from datetime import datetime

def decorated_with_reverse_datetime(lst):
    for value, time in lst:
        yield (datetime.max - time, value, time)


l1 = [("a1", datetime(2020, 12, 13, 12, 40)),
      ("b1", datetime(2020, 12, 13, 12, 30)),
      ("c1", datetime(2020, 12, 13, 12, 20)),
      ("d1", datetime(2020, 12, 13, 12, 10))]

l2 = [("a2", datetime(2020, 12, 13, 12, 32)),
      ("b2", datetime(2020, 12, 13, 12, 24)),
      ("c2", datetime(2020, 12, 13, 12, 9))]

l3 = [("a3", datetime(2020, 12, 13, 12, 35)),
      ("b3", datetime(2020, 12, 13, 12, 18)),
      ("c3", datetime(2020, 12, 13, 12, 16))]

data = [l1, l2, l3]

sorted_tuples = merge(*map(decorated_with_reverse_datetime, data))
undecorated = (tup[1:] for tup in sorted_tuples)
out = list(islice(undecorated, 5))

print(out)
[('a1', datetime.datetime(2020, 12, 13, 12, 40)),
 ('a3', datetime.datetime(2020, 12, 13, 12, 35)),
 ('a2', datetime.datetime(2020, 12, 13, 12, 32)),
 ('b1', datetime.datetime(2020, 12, 13, 12, 30)),
 ('b2', datetime.datetime(2020, 12, 13, 12, 24))]

您可以将链式生成器想象成一个管道,在需要时输出会从链式生成器中提取数据,因此只需对数据进行最低限度的操作。有关生成器使用的更多信息和想法,请参阅一篇有趣的文章。

这里是一种有效的方法,使用它可以让您惰性地合并已排序的列表

(编辑:我刚刚意识到我误读了问题的一部分-最近的项目,所以时间较长的项目,在左边,在列表的开头,而不是像我想象的那样在末尾。所以,同样的事情,但我们甚至不必按相反的顺序重复列表):

我们将列表交给
merge
,它将惰性地对它们进行迭代,每次取
时间较大的元组

时间是每个元组中索引1处的值,因此
key=itemgetter(1)

merge
的默认行为是获取具有最小值的项,因此我们必须使用
reverse=True
告诉它选择最大值

然后,我们使用
islice
从中获取第一个(这里是5个)项目,并将其转换为一个列表

因此,由于所有内容都基于迭代器,因此仅从列表中检索必要的项


如果元组按照相反的顺序排序,正如我最初想象的那样,最新的元组位于列表的末尾:我们必须以相反的顺序在列表上迭代:

from heapq import merge
from itertools import islice
from operator import itemgetter

l1 = [("a1", 10),("b1", 20),("c1", 30),("d1", 40)]
l2 = [("a2", 9),("b2", 24),("c2", 32)]
l3 = [("a3", 16),("b3", 18),("c3", 35)]

data = [l1, l2, l3]

out = list(islice(merge(*map(reversed, data), key=itemgetter(1), reverse=True), 5))

print(out)
# [('d1', 40), ('c3', 35), ('c2', 32), ('c1', 30), ('b2', 24)]

为了回答您的最后一点意见,这里有一个解决方案适用于早于3.5的Python版本,在引入
反向
heapq.merge
的关键字参数之前

我们的想法仍然是使用迭代器和生成器表达式,以便每次访问和处理一个数据段。关键不是什么大问题