Подтвердить что ты не робот

Как отсортировать список с положительными значениями перед негативами со значениями, отсортированными соответственно?

У меня есть список, содержащий смесь положительных и отрицательных чисел, как показано ниже:

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?

4b9b3361

Ответ 1

Вы можете просто использовать обычную сортировку, а затем делите пополам список в 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]

Ответ 2

Просто сравните разные способы.

Результаты:

> 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()

Ответ 3

Создайте два списка: одно с положительным значением и другое с отрицательными значениями, а затем отсортируйте содержимое каждого списка так, как вам нравится. Например:

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)

Ответ 4

Вы можете просто отсортировать по отрицательному элементу обратный элемент:

from __future__ import division

sorted(lst, key=lambda i: 0 if i == 0 else -1 / i)

Взятие инверсных переключателей порядка величин (большее число посередине, меньшее по внешности). Взятие отрицательного числа отменяет порядок (сначала положительные, отрицательные).

Имейте в виду размер ваших номеров, и если они вызовут проблемы с чрезмерным или недостаточным уровнем.

Ответ 5

Создайте два отдельных списка. Одно положительное значение с отрицательными значениями. сортировать отрицательный список, затем объединить их вместе:

>>> 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]
>>> 

Ответ 6

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)

И если вам не нужно использовать список, но довольны массивами numpy, вам не придется оплачивать расходы на кастинг, т.е.

import numpy as np
ar = np.array([1, -2, 10, -12, -4, -5, 9, 2])
ar = np.concatenate([np.sort(ar[ar >= 0]), np.sort(ar[ar < 0])], axis = 0)
print(ar)

Ответ 7

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])

Ответ 8

Престижность к 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]))

Ответ 9

Я не знаю, является ли это самым 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))

Ответ 10

Сортировка списка на месте дважды:

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 является стабильной. Это означает, что элементы с одинаковым значением или ключ остаются в одном порядке. Первая сортировка помещает все предметы в порядок от самых маленьких до самых больших. Для второго сортирования все элементы < 0 получить ключ от True, все элементы >= 0 получить ключ от False. Поскольку True (1) > False (0), вторая сортировка перемещает все отрицательные элементы до конца, не изменяя порядок отрицательных элементов.

Ответ 11

* Вот еще одно решение: *

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)