我有一个包含正数和负数混合的列表,如下所示
lst = [1, -2, 10, -12, -4, -5, 9, 2]
我想要完成的是用负数前面的正数对列表进行排序,也分别排序。
期望的输出:
[1, 2, 9, 10, -12, -5, -4, -2]
我能够找出第一部分排序,其中正数和负数之前,不幸的是,这并没有分别对正数和负数进行排序。
lst = [1, -2, 10, -12, -4, -5, 9, 2]
lst = sorted(lst, key=lambda o: not abs(o) == o)
print(lst)
>>> [1, 10, 2, 9, -2, -12, -4, -5]
如何使用pythonic解决方案实现所需的排序?
答案 0 :(得分:62)
您可以使用常规排序,然后在0:
处将列表二等分>>> lst
[1, -2, 10, -12, -4, -5, 9, 2]
>>> from bisect import bisect
>>> lst.sort()
>>> i = bisect(lst, 0) # use `bisect_left` instead if you want zeroes first
>>> lst[i:] + lst[:i]
[1, 2, 9, 10, -12, -5, -4, -2]
此处的最后一行利用切片不变lst == lst[:n] + lst[n:]
另一个选择是使用元组作为排序键,并依赖元组的lexicographical顺序:
>>> sorted(lst, key=lambda x: (x<0, x)) # use <= instead if you want zeroes last
[1, 2, 9, 10, -12, -5, -4, -2]
答案 1 :(得分:9)
只是比较不同的方式。
结果:
> Shuffle cost comparison small
shuffle_lst: 0.001181483967229724
shuffle_ar: 0.014688121969811618
> Shuffle cost comparison medium
shuffle_lst: 0.572294642101042
shuffle_ar: 0.3266364939045161
> Shuffle cost comparison large
shuffle_lst: 26.5786890439922
shuffle_ar: 6.284286553971469
+cost -cost
bisectme: 0.004252934013493359 0.003071450046263635
lexicon: 0.010936842067167163 0.009755358099937439
compreh.: 0.0071560649666935205 0.005974580999463797
arrayme: 0.03787591797299683 0.023187796003185213
nplexicon: 0.022204622975550592 0.007516501005738974
npbisect: 0.023507782025262713 0.008819660055451095
+cost -cost
bisectme: 7.716002315981314 7.143707673880272
lexicon: 22.17862514301669 21.606330500915647
compreh.: 8.690494343056343 8.118199700955302
arrayme: 1.5029839979251847 1.1763475040206686
nplexicon: 2.0811527019832283 1.7545162080787122
npbisect: 1.3076487149810418 0.9810122210765257
+cost -cost
bisectme: 180.77819497592282 154.19950593193062
arrayme: 22.476932613993995 16.192646060022525
nplexicon: 41.74795828794595 35.46367173397448
npbisect: 20.13856932707131 13.85428277309984
代码:
import sys
import numpy as np
from timeit import timeit
from bisect import bisect
from random import shuffle
def shuffle_lst():
np.random.shuffle(lst)
def shuffle_ar():
np.random.shuffle(ar)
def bisectme():
np.random.shuffle(lst)
lst.sort()
i = bisect(lst, 0)
return lst[i:] + lst[:i]
def lexicon():
np.random.shuffle(lst)
return sorted(lst, key=lambda x: (x < 0, x))
def comprehension():
np.random.shuffle(lst)
return sorted([i for i in lst if i > 0]) + sorted([i for i in lst if i < 0])
def arrayme():
np.random.shuffle(ar)
return np.concatenate([np.sort(ar[ar >= 0]), np.sort(ar[ar < 0])], axis=0)
def nplexicon():
np.random.shuffle(ar)
return ar[np.lexsort((ar, ar < 0))]
def numpybisect():
np.random.shuffle(ar)
ar.sort()
i = ar.__abs__().argmin()
return np.concatenate((ar[i:], ar[:i]))
nloops = 1000
lst = list(range(-10**1, 0, 1)) + list(range(10**1, -1, -1))
ar = np.array(lst)
print("> Shuffle cost comparison small")
cost_shuffle_list_small = timeit(shuffle_lst, number=nloops)
print("shuffle_lst:", cost_shuffle_list_small)
cost_shuffle_array_small = timeit(shuffle_ar, number=nloops)
print("shuffle_ar:", cost_shuffle_array_small)
lst = list(range(-10**4, 0, 1)) + list(range(10**4, -1, -1))
ar = np.array(lst)
print("> Shuffle cost comparison medium")
cost_shuffle_list_medium = timeit(shuffle_lst, number=nloops)
print("shuffle_lst:", cost_shuffle_list_medium)
cost_shuffle_array_medium = timeit(shuffle_ar, number=nloops)
print("shuffle_ar:", cost_shuffle_array_medium)
nloops = 100
lst = list(range(-10**6, 0, 1)) + list(range(10**6, -1, -1))
ar = np.array(lst)
print("> Shuffle cost comparison large")
cost_shuffle_list_large = timeit(shuffle_lst, number=nloops)
print("shuffle_lst:", cost_shuffle_list_large)
cost_shuffle_array_large = timeit(shuffle_ar, number=nloops)
print("shuffle_ar:", cost_shuffle_array_large)
print()
nloops = 1000
## With small lists/arrays
lst = list(range(-10**1, 0, 1)) + list(range(10**1, -1, -1))
ar = np.array(lst)
print("\t\t\t\t\tw/o pen.\t\t\t\tw. pen.")
foo = timeit(bisectme, number=nloops)
print("bisectme:\t", foo, "\t", foo - cost_shuffle_list_small)
foo = timeit(lexicon, number=nloops)
print("lexicon:\t", foo, "\t", foo - cost_shuffle_list_small)
foo = timeit(comprehension, number=nloops)
print("compreh.:\t", foo, "\t", foo - cost_shuffle_list_small)
foo = timeit(arrayme, number=nloops)
print("arrayme:\t", foo, "\t", foo - cost_shuffle_array_small)
foo = timeit(nplexicon, number=nloops)
print("nplexicon:\t", foo, "\t", foo - cost_shuffle_array_small)
foo = timeit(numpybisect, number=nloops)
print("npbisect:\t", foo, "\t", foo - cost_shuffle_array_small)
print()
## With medium lists/arrays
lst = list(range(-10**4, 0, 1)) + list(range(10**4, -1, -1))
ar = np.array(lst)
print("\t\t\t\t\tw/o cost\t\t\t\tw. cost")
foo = timeit(bisectme, number=nloops)
print("bisectme:\t", foo, "\t", foo - cost_shuffle_list_medium)
foo = timeit(lexicon, number=nloops)
print("lexicon:\t", foo, "\t", foo - cost_shuffle_list_medium)
foo = timeit(comprehension, number=nloops)
print("compreh.:\t", foo, "\t", foo - cost_shuffle_list_medium)
foo = timeit(arrayme, number=nloops)
print("arrayme:\t", foo, "\t", foo - cost_shuffle_array_medium)
foo = timeit(nplexicon, number=nloops)
print("nplexicon:\t", foo, "\t", foo - cost_shuffle_array_medium)
foo = timeit(numpybisect, number=nloops)
print("npbisect:\t", foo, "\t", foo - cost_shuffle_array_medium)
print()
## With large lists/arrays
nloops = 100
lst = list(range(-10**6, 0, 1)) + list(range(10**6, -1, -1))
ar = np.array(lst)
print("\t\t\t\t\tw/o cost\t\t\t\tw. cost")
foo = timeit(bisectme, number=nloops)
print("bisectme:\t", foo, "\t", foo - cost_shuffle_list_large)
foo = timeit(arrayme, number=nloops)
print("arrayme:\t", foo, "\t", foo - cost_shuffle_array_large)
foo = timeit(nplexicon, number=nloops)
print("nplexicon:\t", foo, "\t", foo - cost_shuffle_array_large)
foo = timeit(numpybisect, number=nloops)
print("npbisect:\t", foo, "\t", foo - cost_shuffle_array_large)
print()
答案 2 :(得分:6)
创建两个列表,一个列表为正值,另一个列表为负值,然后按照您喜欢的方式对每个列表的内容进行排序。例如:
my_list = [1, -2, 10, -12, -4, -5, 9, 2]
pos_list, neg_list = [], []
for item in my_list:
if item < 0:
neg_list.append(item)
else:
pos_list.append(item)
final_list = sorted(pos_list) + sorted(neg_list)
答案 3 :(得分:5)
你可以按元素反转的负数排序:
from __future__ import division
sorted(lst, key=lambda i: 0 if i == 0 else -1 / i)
采用反向开关的大小顺序(中间较大的数字,外部较小的数字)。采取负面反转顺序(先是积极,最后是负面)。
请注意您的课程数量,以及是否会导致任何过度或下溢问题。
答案 4 :(得分:4)
创建两个单独的列表。一个正值表示负值。对负面列表进行排序,然后将它们连接在一起:
>>> lst = [1, -2, 10, -12, -4, -5, 9, 2]
>>> sorted([i for i in lst if i > 0]) + sorted([i for i in lst if i =< 0])
[1, 2, 9, 10, -12, -5, -4, -2]
>>>
答案 5 :(得分:3)
data Nil = Nil
data Cons a = Cons a (List a)
type List a = Cons a :|: Nil
如果您不必使用列表但对numpy数组感到满意,那么您无需支付铸造成本,即
import numpy as np
lst = [1, -2, 10, -12, -4, -5, 9, 2]
ar = np.array(lst)
lst = list(np.concatenate([np.sort(ar[ar >= 0]), np.sort(ar[ar < 0], reverse = True)], axis = 0))
print(lst)
答案 6 :(得分:3)
import numpy as np
l = np.array([1, -2, 10, -12, -4, -5, 9, 2])
l[np.lexsort((l, l < 0))]
array([ 1, 2, 9, 10, -12, -5, -4, -2])
答案 7 :(得分:2)
感谢wmin的解决方案(接受的答案)的逻辑,这很棒。因此,为了完整性,对此的类似答案,但基于numpy,除了小列表/数组之外的其他任何事情都明显更快,如下所示:
lst = [1, -2, 10, -12, -4, -5, 9, 2]
ar = np.array(lst)
ar.sort()
i = ar.__abs__().argmin()
np.concatenate((ar[i:], ar[:i]))
答案 8 :(得分:2)
我不知道它是大多数 Pythonic,它当然没有任何铃声和口哨,但IMO是一个清晰易懂的代码:
lst = [1, -2, 10, -12, -4, -5, 9, 2]
pos = list()
neg = list()
for i in lst:
neg.append(i) if i < 0 else pos.append(i)
print(sorted(pos) + sorted(neg))
答案 9 :(得分:1)
将列表排序两次,如下所示:
lst = [1, -2, 10, -12, -4, -5, 9, 2]
lst.sort()
lst.sort(key=int(0).__gt__) # key is True for items <= 0
这利用了python sort
函数/方法稳定的事实。这意味着具有相同值或键的项目保持相同的顺序。第一种排序将所有项目按从小到大的顺序排列。对于第二种,所有项目&lt; 0得到一个True键,所有项&gt; = 0得到一个False键。因为True(1)&gt;假(0),第二种排序将所有负项移动到最后,而不更改否定项的顺序。
答案 10 :(得分:0)
*这是另一种解决方案:*
lst = [1, -2, 10, -12, -4, -5, 9, 2] # list of values.
x = sorted(lst) # x : [-12, -5, -4, -2, 1, 2, 9, 10]
k, m = [], [] # k : [1, 2, 9, 10] # M : [-12, -5, -4, -2]
for i in x:
if i > 0:
k.append(i)
else:
m.append(i)
w = k + m # w : [1, 2, 9, 10, -12, -5, -4, -2]
print(w)