在Python中组合两个排序列表
我有两个对象列表。每个列表都已按datetime类型的对象属性排序。我想把这两个列表合并成一个排序列表。排序是最好的方法还是Python中有更智能的方法?这只是合并。将每个列表视为一个堆栈,并连续弹出两个堆栈头中较小的一个,将该项添加到结果列表中,直到其中一个堆栈为空。然后将所有剩余的项目添加到结果列表中。好吧,简单的方法(将两个列表合并成一个大列表并排序)将是O(N*log(N))复杂度。另一方面,如果手动实现合并(我不知道pythonlibs中是否有现成的代码,但我不是专家),复杂性将是O(N),这显然更快。 巴里·凯利(Barry Kelly)在文章中很好地描述了这个想法。在Python中组合两个排序列表,python,list,sorting,Python,List,Sorting,我有两个对象列表。每个列表都已按datetime类型的对象属性排序。我想把这两个列表合并成一个排序列表。排序是最好的方法还是Python中有更智能的方法?这只是合并。将每个列表视为一个堆栈,并连续弹出两个堆栈头中较小的一个,将该项添加到结果列表中,直到其中一个堆栈为空。然后将所有剩余的项目添加到结果列表中。好吧,简单的方法(将两个列表合并成一个大列表并排序)将是O(N*log(N))复杂度。另一方面,如果手动实现合并(我不知道pythonlibs中是否有现成的代码,但我不是专家),复杂性将是O(
def compareDate(obj1,obj2):
def compareDate(obj1, obj2):
if obj1.getDate() < obj2.getDate():
return -1
elif obj1.getDate() > obj2.getDate():
return 1
else:
return 0
list = list1 + list2
list.sort(compareDate)
如果obj1.getDate()obj2.getDate():
返回1
其他:
返回0
列表=列表1+列表2
列表.排序(比较)
将对列表进行适当排序。为比较两个对象定义自己的函数,并将该函数传递到内置的排序函数中
不要使用冒泡排序,它的性能很差。使用合并排序的“合并”步骤,它在O(n)时间内运行 从(伪代码):
这是两个排序列表的简单合并。看看下面的示例代码,它合并了两个已排序的整数列表
#!/usr/bin/env python
## merge.py -- Merge two sorted lists -*- Python -*-
## Time-stamp: "2009-01-21 14:02:57 ghoseb"
l1 = [1, 3, 4, 7]
l2 = [0, 2, 5, 6, 8, 9]
def merge_sorted_lists(l1, l2):
"""Merge sort two sorted lists
Arguments:
- `l1`: First sorted list
- `l2`: Second sorted list
"""
sorted_list = []
# Copy both the args to make sure the original lists are not
# modified
l1 = l1[:]
l2 = l2[:]
while (l1 and l2):
if (l1[0] <= l2[0]): # Compare both heads
item = l1.pop(0) # Pop from the head
sorted_list.append(item)
else:
item = l2.pop(0)
sorted_list.append(item)
# Add the remaining of the lists
sorted_list.extend(l1 if l1 else l2)
return sorted_list
if __name__ == '__main__':
print merge_sorted_lists(l1, l2)
#/usr/bin/env python
##merge.py--合并两个排序列表-*-Python-*-
##时间戳:“2009-01-2114:02:57 ghoseb”
l1=[1,3,4,7]
l2=[0,2,5,6,8,9]
def合并排序列表(l1、l2):
“”“合并排序两个已排序的列表
论据:
-`l1`:第一个排序的列表
-`l2`:第二个排序列表
"""
已排序的_列表=[]
#复制两个参数以确保原始列表不存在
#修改
l1=l1[:]
l2=l2[:]
而(l1和l2):
如果(l1[0]人们似乎过于复杂化了。只需将这两个列表合并,然后对它们进行排序:
>>> l1 = [1, 3, 4, 7]
>>> l2 = [0, 2, 5, 6, 8, 9]
>>> l1.extend(l2)
>>> sorted(l1)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
..或更短(且无需修改l1
):
…简单!另外,它只使用两个内置函数,因此假设列表的大小合理,它应该比在循环中实现排序/合并更快。更重要的是,上面的代码要少得多,可读性也很强
如果您的列表很大(我猜超过几十万),使用替代/自定义排序方法可能会更快,但可能会先进行其他优化(例如,不存储数百万个datetime
对象)
使用timeit.Timer().repeat()
(它将函数重复1000000次),我粗略地对照解决方案对其进行了基准测试,并且排序(l1+l2)
大大加快了速度:
merge\u sorted\u list
take
[9.7439379692077637, 9.8844599723815918, 9.552299976348877]
[2.860386848449707, 2.7589840888977051, 2.7682540416717529]
sorted(l1+l2)
take
[9.7439379692077637, 9.8844599723815918, 9.552299976348877]
[2.860386848449707, 2.7589840888977051, 2.7682540416717529]
解决方案中有一个轻微的缺陷,使其为O(n**2),而不是O(n)。
问题在于,这正在执行:
item = l1.pop(0)
对于链表或deques,这将是一个O(1)操作,因此不会影响复杂性,但由于python列表是作为向量实现的,因此它将l1的其余元素复制到左一个空格,即O(n)操作。由于每次通过列表都会执行此操作,因此它将O(n)算法转换为O(n**2)这可以通过使用一种不改变源列表,只跟踪当前位置的方法来纠正
我已经尝试过将一个修正的算法与一个简单的排序(l1+l2)进行基准测试,正如
对于不同大小的列表,我得到以下计时(重复100次):
因此,事实上,看起来dbr是正确的,除非您希望得到非常大的列表,否则最好只使用sorted(),尽管它的算法复杂度更差。收支平衡点是每个源列表中大约有100万项(总共200万项)
不过,合并方法的一个优点是,作为生成器重写非常简单,它将使用更少的内存(不需要中间列表)
[编辑]
我在一个更接近问题的情况下重试了这个问题——使用一个包含字段“date
”的对象列表,该字段是一个datetime对象。
将上述算法更改为与.date
进行比较,并将排序方法更改为:
return sorted(l1 + l2, key=operator.attrgetter('date'))
这确实改变了一些事情。比较更昂贵意味着相对于实现的恒定时间速度,我们执行的数字变得更重要。这意味着merge弥补了损失,取代sort()方法的是100000项。比较基于更复杂的对象(比如大字符串或列表)可能会进一步改变这种平衡
# items: 1000 10000 100000 1000000[1]
merge : 0.161 2.034 23.370 253.68
sort : 0.111 1.523 25.223 313.20
[1] :注意:事实上,我只对1000000个项目重复了10次,并相应地放大,因为速度相当慢
在Python中有没有更聪明的方法来实现这一点
这一点还没有提到,所以我将继续——python 2.6+的heapq模块中有一个。如果您希望做的只是完成一些事情,这可能是一个更好的主意。当然,如果您想实现自己的,合并排序的合并是一个不错的选择
>>> list1 = [1, 5, 8, 10, 50]
>>> list2 = [3, 4, 29, 41, 45, 49]
>>> from heapq import merge
>>> list(merge(list1, list2))
[1, 3, 4, 5, 8, 10, 29, 41, 45, 49, 50]
给你
输出:
2008-12-05 02:00:00
2008-12-31 23:00:00
2009-01-01 13:00:00
2009-01-02 12:00:00
2009-01-03 05:00:00
2009-01-04 15:00:00
我打赌这比任何花哨的纯Python合并算法都要快,即使对于大数据也是如此。Python 2.6的heapq.merge
完全是另一回事。长话短说,除非len(l1+l2)~1000000
使用:
L = l1 + l2
L.sort()
可以找到图的说明和源代码
该图形由以下命令生成:
$ python make-figures.py --nsublists 2 --maxn=0x100000 -s merge_funcs.merge_26 -s merge_funcs.sort_builtin
递归实现低于。平均性能为O(n)
def merge_sorted_list(A、B、sorted_list=None):
如果已排序\u列表==无:
已排序的_列表=[]
切片索引=0
对于A中的元素:
if元素Python的
from datetime import datetime
from itertools import chain
from operator import attrgetter
class DT:
def __init__(self, dt):
self.dt = dt
list1 = [DT(datetime(2008, 12, 5, 2)),
DT(datetime(2009, 1, 1, 13)),
DT(datetime(2009, 1, 3, 5))]
list2 = [DT(datetime(2008, 12, 31, 23)),
DT(datetime(2009, 1, 2, 12)),
DT(datetime(2009, 1, 4, 15))]
list3 = sorted(chain(list1, list2), key=attrgetter('dt'))
for item in list3:
print item.dt
2008-12-05 02:00:00
2008-12-31 23:00:00
2009-01-01 13:00:00
2009-01-02 12:00:00
2009-01-03 05:00:00
2009-01-04 15:00:00
L = l1 + l2
L.sort()
$ python make-figures.py --nsublists 2 --maxn=0x100000 -s merge_funcs.merge_26 -s merge_funcs.sort_builtin
def merge_sorted_lists(A, B, sorted_list = None):
if sorted_list == None:
sorted_list = []
slice_index = 0
for element in A:
if element <= B[0]:
sorted_list.append(element)
slice_index += 1
else:
return merge_sorted_lists(B, A[slice_index:], sorted_list)
return sorted_list + B
def merge_sorted_lists_as_generator(A, B):
slice_index = 0
for element in A:
if element <= B[0]:
slice_index += 1
yield element
else:
for sorted_element in merge_sorted_lists_as_generator(B, A[slice_index:]):
yield sorted_element
return
for element in B:
yield element
def merge_arrays(a, b):
l= []
while len(a) > 0 and len(b)>0:
if a[0] < b[0]: l.append(a.pop(0))
else:l.append(b.pop(0))
l.extend(a+b)
print( l )
import random
n=int(input("Enter size of table 1")); #size of list 1
m=int(input("Enter size of table 2")); # size of list 2
tb1=[random.randrange(1,101,1) for _ in range(n)] # filling the list with random
tb2=[random.randrange(1,101,1) for _ in range(m)] # numbers between 1 and 100
tb1.sort(); #sort the list 1
tb2.sort(); # sort the list 2
fus=[]; # creat an empty list
print(tb1); # print the list 1
print('------------------------------------');
print(tb2); # print the list 2
print('------------------------------------');
i=0;j=0; # varialbles to cross the list
while(i<n and j<m):
if(tb1[i]<tb2[j]):
fus.append(tb1[i]);
i+=1;
else:
fus.append(tb2[j]);
j+=1;
if(i<n):
fus+=tb1[i:n];
if(j<m):
fus+=tb2[j:m];
print(fus);
# this code is used to merge two sorted lists in one sorted list (FUS) without
#sorting the (FUS)
def merge(lst1,lst2):
len1=len(lst1)
len2=len(lst2)
i,j=0,0
while(i<len1 and j<len2):
if(lst1[i]<lst2[j]):
yield lst1[i]
i+=1
else:
yield lst2[j]
j+=1
if(i==len1):
while(j<len2):
yield lst2[j]
j+=1
elif(j==len2):
while(i<len1):
yield lst1[i]
i+=1
l1=[1,3,5,7]
l2=[2,4,6,8,9]
mergelst=(val for val in merge(l1,l2))
print(*mergelst)
def merge_sort(a,b):
pa = 0
pb = 0
result = []
while pa < len(a) and pb < len(b):
if a[pa] <= b[pb]:
result.append(a[pa])
pa += 1
else:
result.append(b[pb])
pb += 1
remained = a[pa:] + b[pb:]
result.extend(remained)
return result
def merge_lists(L1, L2):
"""
L1, L2: sorted lists of numbers, one of them could be empty.
returns a merged and sorted list of L1 and L2.
"""
# When one of them is an empty list, returns the other list
if not L1:
return L2
elif not L2:
return L1
result = []
i = 0
j = 0
for k in range(len(L1) + len(L2)):
if L1[i] <= L2[j]:
result.append(L1[i])
if i < len(L1) - 1:
i += 1
else:
result += L2[j:] # When the last element in L1 is reached,
break # append the rest of L2 to result.
else:
result.append(L2[j])
if j < len(L2) - 1:
j += 1
else:
result += L1[i:] # When the last element in L2 is reached,
break # append the rest of L1 to result.
return result
L1 = [1, 3, 5]
L2 = [2, 4, 6, 8]
merge_lists(L1, L2) # Should return [1, 2, 3, 4, 5, 6, 8]
merge_lists([], L1) # Should return [1, 3, 5]
def merge(l1, l2):
m, m2 = len(l1), len(l2)
newList = []
l, r = 0, 0
while l < m and r < m2:
if l1[l] < l2[r]:
newList.append(l1[l])
l += 1
else:
newList.append(l2[r])
r += 1
return newList + l1[l:] + l2[r:]
def merge_sorted_lists(listA,listB,func):
merged = list()
iA = 0
iB = 0
while True:
hasA = iA < len(listA)
hasB = iB < len(listB)
if not hasA and not hasB:
break
valA = None if not hasA else listA[iA]
valB = None if not hasB else listB[iB]
a = None if not hasA else func(valA)
b = None if not hasB else func(valB)
if (not hasB or a<b) and hasA:
merged.append(valA)
iA += 1
elif hasB:
merged.append(valB)
iB += 1
return merged
def merge_sorted_list(nums1: list, nums2:list) -> list:
m = len(nums1)
n = len(nums2)
nums1 = nums1.copy()
nums2 = nums2.copy()
nums1.extend([0 for i in range(n)])
while m > 0 and n > 0:
if nums1[m-1] >= nums2[n-1]:
nums1[m+n-1] = nums1[m-1]
m -= 1
else:
nums1[m+n-1] = nums2[n-1]
n -= 1
if n > 0:
nums1[:n] = nums2[:n]
return nums1
l1 = [1, 3, 4, 7]
l2 = [0, 2, 5, 6, 8, 9]
print(merge_sorted_list(l1, l2))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
def in_built_sort(list1, list2):
// time complexity : O(nlog n)
return sorted(list1 + list2)
def custom_sort(list1, list2):
// time complexity : O(n)
merged_list_size = len(list1) + len(list2)
merged_list = [None] * merged_list_size
current_index_list1 = 0
current_index_list2 = 0
current_index_merged = 0
while current_index_merged < merged_list_size:
if (not current_index_list1 >= len(list1) and (current_index_list2 >= len(list2) or list1[current_index_list1] < list2[current_index_list2])):
merged_list[current_index_merged] = list1[current_index_list1]
current_index_list1 += 1
else:
merged_list[current_index_merged] = list2[current_index_list2]
current_index_list2 += 1
current_index_merged += 1
return merged_list
print(timeit.timeit(stmt=in_built_sort, number=10)) // 250.44088469999997 O(nlog n)
print(timeit.timeit(stmt=custom_sort, number=10)) // 125.82338159999999 O(n)