我有一堆排序的对象列表和一个比较函数
class Obj :
def __init__(p) :
self.points = p
def cmp(a, b) :
return a.points < b.points
a = [Obj(1), Obj(3), Obj(8), ...]
b = [Obj(1), Obj(2), Obj(3), ...]
c = [Obj(100), Obj(300), Obj(800), ...]
result = magic(a, b, c)
assert result == [Obj(1), Obj(1), Obj(2), Obj(3), Obj(3), Obj(8), ...]
magic
的样子是什么?我目前的实施是
def magic(*args) :
r = []
for a in args : r += a
return sorted(r, cmp)
但效率很低。更好的答案?
答案 0 :(得分:14)
Python标准库为它提供了一种方法:heapq.merge
正如文档所说,它与使用itertools非常相似(但有更多限制);如果您不能忍受这些限制(或者如果您不使用Python 2.6),您可以执行以下操作:
sorted(itertools.chain(args), cmp)
但是,我认为它与您自己的解决方案具有相同的复杂性,尽管使用迭代器应该会给出一些非常好的优化和速度提升。
答案 1 :(得分:2)
使用bisect
模块。从文档:“此模块支持按排序顺序维护列表,而无需在每次插入后对列表进行排序。”
import bisect
def magic(*args):
r = []
for a in args:
for i in a:
bisect.insort(r, i)
return r
答案 2 :(得分:2)
您可以使用[heap](http://en.wikipedia.org/wiki/Heap_(data_structure)。
,而不是使用列表插入是O(log(n)),因此合并a,b和c将为O(n log(n))
在Python中,您可以使用heapq
module。
答案 3 :(得分:2)
我喜欢Roberto Liffredo的回答。我不知道heapq.merge()。 Hmmmph。
以下是使用Roberto领导的完整解决方案:
class Obj(object):
def __init__(self, p) :
self.points = p
def __cmp__(self, b) :
return cmp(self.points, b.points)
def __str__(self):
return "%d" % self.points
a = [Obj(1), Obj(3), Obj(8)]
b = [Obj(1), Obj(2), Obj(3)]
c = [Obj(100), Obj(300), Obj(800)]
import heapq
sorted = [item for item in heapq.merge(a,b,c)]
for item in sorted:
print item
或者:
for item in heapq.merge(a,b,c):
print item
答案 4 :(得分:0)
我不知道它是否会更快,但您可以通过以下方式简化它:
def GetObjKey(a):
return a.points
return sorted(a + b + c, key=GetObjKey)
如果您愿意,当然也可以使用cmp
而不是key
。
答案 5 :(得分:0)
使用已排序的一行解决方案:
def magic(*args):
return sorted(sum(args,[]), key: lambda x: x.points)
IMO这个解决方案非常易读。
使用heapq模块,它可能更有效,但我还没有测试过它。您不能在heapq中指定cmp / key函数,因此必须实现Obj以进行隐式排序。
import heapq
def magic(*args):
h = []
for a in args:
heapq.heappush(h,a)
return [i for i in heapq.heappop(h)
答案 6 :(得分:0)
在这里:列表的完全功能合并排序(根据我的排序here改编):
def merge(*args):
import copy
def merge_lists(left, right):
result = []
while left and right:
which_list = (left if left[0] <= right[0] else right)
result.append(which_list.pop(0))
return result + left + right
lists = list(args)
while len(lists) > 1:
left, right = copy.copy(lists.pop(0)), copy.copy(lists.pop(0))
result = merge_lists(left, right)
lists.append(result)
return lists.pop(0)
这样称呼:
merged_list = merge(a, b, c)
for item in merged_list:
print item
为了更好的衡量,我会对你的Obj课程进行一些修改:
class Obj(object):
def __init__(self, p) :
self.points = p
def __cmp__(self, b) :
return cmp(self.points, b.points)
def __str__(self):
return "%d" % self.points
self
传递给__init__()
__cmp__
成为会员功能str()
成员函数以将Obj
显示为字符串答案 7 :(得分:0)
我问了一个类似的问题并得到了一些很好的答案:
该问题的最佳解决方案是合并算法的变体,您可以在这里阅读:
答案 8 :(得分:0)
以下是在O(n)比较中运行的函数示例。
你可以通过创建a和b迭代器并递增它们来加快速度。
我只是简单地调用了两次函数来合并3个列表:
def zip_sorted(a, b):
'''
zips two iterables, assuming they are already sorted
'''
i = 0
j = 0
result = []
while i < len(a) and j < len(b):
if a[i] < b[j]:
result.append(a[i])
i += 1
else:
result.append(b[j])
j += 1
if i < len(a):
result.extend(a[i:])
else:
result.extend(b[j:])
return result
def genSortedList(num,seed):
result = []
for i in range(num):
result.append(i*seed)
return result
if __name__ == '__main__':
a = genSortedList(10000,2.0)
b = genSortedList(6666,3.0)
c = genSortedList(5000,4.0)
d = zip_sorted(zip_sorted(a,b),c)
print d
但是, heapq.merge 使用此方法的混合并堆叠所有列表的当前元素,因此应该执行得更好