是否有可能以完全相同的方式sorting两个列表(它们相互引用)?
好的,这可能不是最聪明的想法,但是如果这是可能的,我有点好奇。 说我有两个名单:
list1 = [3,2,4,1, 1] list2 = [three, two, four, one, one2]
如果我运行list1.sort()
,它会将它sorting到[1,1,2,3,4]
但有一种方法来保持list2同步以及(所以我可以说第4项属于'三')? 我的问题是我有一个相当复杂的程序,与列表工作正常,但我需要开始引用一些数据。 我知道这是一个字典完美的情况,但我试图避免在我的处理字典,因为我需要sorting的关键值(如果我必须使用字典,我知道如何使用它们)。
基本上这个程序的本质是,数据是随机的(如上图),我需要对它进行sorting,处理,然后发送结果(顺序无关紧要,但用户需要知道哪个结果属于哪个键)。 我想先把它放在字典里,然后sorting一个列表,但是如果订单不被保留(在将结果传达给用户时可能会产生影响),我将无法区分具有相同值的项目。 所以理想情况下,一旦我得到清单,我宁愿找出一种方法来将两个清单sorting在一起。 这可能吗?
解决这个问题的一个经典方法是使用“装饰,sorting,未打包”成语,这是使用python的内置zip
函数特别简单:
>>> list1 = [3,2,4,1, 1] >>> list2 = ['three', 'two', 'four', 'one', 'one2'] >>> list1, list2 = zip(*sorted(zip(list1, list2))) >>> list1 (1, 1, 2, 3, 4) >>> list2 ('one', 'one2', 'two', 'three', 'four')
这些当然不再是清单,但如果它很重要的话,这很容易解决:
>>> list1, list2 = (list(t) for t in zip(*sorted(zip(list1, list2)))) >>> list1 [1, 1, 2, 3, 4] >>> list2 ['one', 'one2', 'two', 'three', 'four']
值得注意的是,上述可能会为简洁而牺牲速度; 占用3行的就地版本在我的机器上对于小列表来说要快一点:
>>> %timeit zip(*sorted(zip(list1, list2))) 100000 loops, best of 3: 3.3 us per loop >>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups) 100000 loops, best of 3: 2.84 us per loop
另一方面,对于更大的列表,单行版本可能会更快:
>>> %timeit zip(*sorted(zip(list1, list2))) 100 loops, best of 3: 8.09 ms per loop >>> %timeit tups = zip(list1, list2); tups.sort(); zip(*tups) 100 loops, best of 3: 8.51 ms per loop
正如Quantum7指出的那样, JSF的build议还是快一点,但是可能只会更快一点,因为Python在内部对所有基于键的sorting都使用了相同的DSU方式 。 它刚刚发生在裸机附近。 (这显示了zip
程序的优化程度!)
我认为基于zip
的方法更灵活,可读性更强,所以我更喜欢它。
您可以使用值作为键对索引进行sorting:
indexes = range(len(list1)) indexes.sort(key=list1.__getitem__)
为了得到有序的索引sorting列表:
sorted_list1 = map(list1.__getitem__, indexes) sorted_list2 = map(list2.__getitem__, indexes)
在你的情况下,你不应该有list1
, list2
,而是一个单一的列表对:
data = [(3, 'three'), (2, 'two'), (4, 'four'), (1, 'one'), (1, 'one2')]
这很容易创build; 在Python中很容易sorting:
data.sort() # sort using a pair as a key
仅按第一个值sorting:
data.sort(key=lambda pair: pair[0])
施瓦茨变换 。 内置的Pythonsorting是稳定的,所以两个1
秒不会造成问题。
>>> l1 = [3, 2, 4, 1, 1] >>> l2 = ['three', 'two', 'four', 'one', 'second one'] >>> zip(*sorted(zip(l1, l2))) [(1, 1, 2, 3, 4), ('one', 'second one', 'two', 'three', 'four')]
我已经使用了senderle给出的答案很长一段时间,直到我发现np.argsort
。 下面是它的工作原理。
# idx works on np.array and not lists. list1 = np.array([3,2,4,1]) list2 = np.array(["three","two","four","one"]) idx = np.argsort(list1) list1 = np.array(list1)[idx] list2 = np.array(list2)[idx]
我觉得这个解决scheme更直观,而且工作得很好。 性能:
def sorting(l1, l2): # l1 and l2 has to be numpy arrays idx = np.argsort(l1) return l1[idx], l2[idx] # list1 and list2 are np.arrays here... %timeit sorting(list1, list2) 100000 loops, best of 3: 3.53 us per loop # This works best when the lists are NOT np.array %timeit zip(*sorted(zip(list1, list2))) 100000 loops, best of 3: 2.41 us per loop # 0.01us better for np.array (I think this is negligible) %timeit tups = zip(list1, list2); tups.sort(); zip(*tups) 100000 loops, best for 3 loops: 1.96 us per loop
即使np.argsort
不是最快的,我觉得使用起来更方便。
关于什么:
list1 = [3,2,4,1, 1] list2 = ['three', 'two', 'four', 'one', 'one2'] sortedRes = sorted(zip(list1, list2), key=lambda x: x[0]) # use 0 or 1 depending on what you want to sort >>> [(1, 'one'), (1, 'one2'), (2, 'two'), (3, 'three'), (4, 'four')]
一种方法是通过对身份[0,1,2,… n]进行sorting来跟踪每个索引的位置
这适用于任何数量的列表。
然后将每个项目移动到其位置。 使用接头是最好的。
list1 = [3,2,4,1, 1] list2 = ['three', 'two', 'four', 'one', 'one2'] index = range(len(list1)) print index '[0, 1, 2, 3, 4]' index.sort(key = list1.__getitem__) print index '[3, 4, 1, 0, 2]' list1[:] = [list1[i] for i in index] list2[:] = [list2[i] for i in index] print list1 print list2 '[1, 1, 2, 3, 4]' "['one', 'one2', 'two', 'three', 'four']"
请注意,我们可以重复列表,甚至没有对它们进行sorting:
list1_iter = (list1[i] for i in index)
您可以使用zip()
和sort()
函数来完成此操作:
Python 2.6.5 (r265:79063, Jun 12 2010, 17:07:01) [GCC 4.3.4 20090804 (release) 1] on cygwin >>> list1 = [3,2,4,1,1] >>> list2 = ['three', 'two', 'four', 'one', 'one2'] >>> zipped = zip(list1, list2) >>> zipped.sort() >>> slist1 = [i for (i, s) in zipped] >>> slist1 [1, 1, 2, 3, 4] >>> slist2 = [s for (i, s) in zipped] >>> slist2 ['one', 'one2', 'two', 'three', 'four']
希望这可以帮助