簡體   English   中英

從中間對列表進行排序的最 Pythonic 方式?

[英]Most Pythonic way to sort a list from middle?

我有一個整數列表。 現在我想從中間排序。 我的意思是:

  1. 如果列表的長度是奇數,則從中間的數字開始;
  2. 如果列表的長度是偶數,則從中間兩個數字中的較大者開始;
  3. 交替取左右(或左右,取決於它們的大小)的數字。 總是先取兩者中較大的一個。

我設法編寫了以下代碼,但僅適用於奇數大小的列表。 為此編寫一個偶數版本並不難,但我覺得必須有更通用和“Pythonic”的方式來編碼。 實際上,我很驚訝以前從未有人問過這個微不足道的問題。

# Odd length, works
lst = [1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0] # Expected output [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

# Even length, doesn't work
#lst = [1, 3, 5, 7, 9, 8, 6, 4, 2, 0] # Expected output [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

mid = len(lst) // 2
dist = 1
res = [lst[mid]]
while dist <= mid:
    res += sorted([lst[mid - dist], lst[mid + dist]], reverse=True)
    dist += 1
assert len(res) == len(lst)
print(res)

注意,第一個數字后面的序列必須遵循距離+-1,+-2,+- [5, 4, 3, 2, 1] 5,4,3,2,1]的預期output是[3, 4, 2, 5, 1] ; [5, 3, 1, 0, 2, 4]的預期 output 是[1, 0, 3, 2, 5, 4]

此外,如果有人可以為 function 提供reverse=TrueFalse選項,那就太好了,這樣用戶就可以決定是先選擇更大還是更小的數字。

嘗試以下(雖然我更喜歡下面的遞歸版本):

lst_odd = [1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0]
lst_even = [1, 3, 5, 7, 9, 8, 6, 4, 2, 0]

def sorted_from_middle(lst, reverse=False):
    left = lst[len(lst)//2-1::-1]
    right = lst[len(lst)//2:]
    output = [right.pop(0)] if len(lst) % 2 else []
    for t in zip(left, right):
        output += sorted(t, reverse=reverse)
    return output

print(sorted_from_middle(lst_odd)) # [10, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1]
print(sorted_from_middle(lst_even)) # [8, 9, 6, 7, 4, 5, 2, 3, 0, 1]
print(sorted_from_middle(lst_odd, True)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(sorted_from_middle(lst_even, True)) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
print(sorted_from_middle([5, 4, 3, 2, 1], True)) # [3, 4, 2, 5, 1]
print(sorted_from_middle([5, 3, 1, 0, 2, 4], True)) # [1, 0, 3, 2, 5, 4]

這個想法right將輸入列表分成left兩部分; 通過首先將最中心的項目(如果有)附加到 output 列表(在代碼中這是通過從right竊取項目來完成),使它們具有相同的長度。 left反轉,以便在leftright中,第一個元素最靠近中心。 然后使用zip()同時取兩個與中心距離為 1 的元素,比較它們,並根據 output 列表對它們進行 append。 然后移動到下一對項目,依此類推。


作為旁注,您也可以使用遞歸 function 來執行此操作,我認為它可以更干凈地處理偶數/奇數情況。

def sorted_from_middle(lst, reverse=False):
    if len(lst) <= 1:
        return lst
    tail = sorted([lst[-1], lst[0]], reverse=reverse)
    return sorted_from_middle(lst[1:-1], reverse) + tail

這個想法基本上只是 1)排除中間元素,如果它是奇數並保存它,然后 2)對由剩余列表前半部分的一個元素向后組織和剩余列表后半部分的另一個元素組成的每一對進行排序; 和 3) 展平將前中間元素添加為第一個元素的對列表(如果有)

import numpy


lst1 = [1, 3, 5, 7, 9, 10, 8, 6, 4, 2, 0]
lst1_out = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
lst2 = [1, 3, 5, 7, 9, 8, 6, 4, 2, 0]
lst2_out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
lst3 = [5, 4, 3, 2, 1]
lst3_out = [3, 4, 2, 5, 1]
lst4 = [5, 3, 1, 0, 2, 4]
lst4_out = [1, 0, 3, 2, 5, 4]

def sort_from_middle(lst,reverse=True):
    lst = lst.copy()
    N = len(lst)
    if N == 1:
        return lst
    elif N == 2:
        return sorted(lst, reverse=reverse)
    else:
        flatten_func = lambda t: [item for sublist in t for item in sublist]
        n = int(numpy.floor(N/2.0))
        x0 = [ lst.pop(n) ] if ((N%2) == 1) else []
        N = len(lst)
        return x0 + flatten_func([ sorted([x1,x2],reverse=reverse) for x1,x2 in zip(lst[int(N/2)-1::-1],lst[int(N/2):]) ])
    

print(lst1)
print(sort_from_middle(lst1))
print(lst1_out)

print(' \n')
print(lst2)
print(sort_from_middle(lst2))
print(lst2_out)

print(' \n')
print(lst3)
print(sort_from_middle(lst3))
print(lst3_out)

print(' \n')
print(lst4)
print(sort_from_middle(lst4))
print(lst4_out)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM