簡體   English   中英

Python-通過將某些項目移到最前面來對列表中的項目進行重新排序,而其余部分保持相同的順序

[英]Python - reordering items in list by moving some items to the front while keeping the rest in the same order

我試圖以以下示例所示的方式對列表中的項目重新排序:

假設重新排序之前的列表是:

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

我想實現一種稱為reorder_list(list, custom_order)的方法reorder_list(list, custom_order)例如:

list1 = reorder_list(list1, [3, 6, 12, 9])
print(list1)

Out: [3, 6, 9, 1, 2, 4, 5, 7, 8, 10]

說明: [3, 6, 12, 9]是我指定的自定義訂單。 12沒有在list1因此將被忽略。 369是在list1 ,所以它們會移動到列表的前面和它們的順序是相同的,如[3, 6, 12, 9] 在其余的項目list1是后369 ,並在原來的順序。

有沒有比實現類似C的循環代碼更簡單的方法(和Python方式)。 就我的目的而言,我更關心代碼的簡單性而不是性能。

def reorder_list(list_main, custom_order):
    # initializing empty list
    list1 = list()

    # to add values of custom list to list1 which are present in main list
    for value in custom_order:
        # add only the values which are present in main list
        if value in list_main:
            list1.append(value)
    # to add remaining element of main list to list1 which are not present in list1
    for value in list_main:
        if value not in list1:
            list1.append(value)

    return  list1

list1 = [1,2,3,4,5,6,7,8,9,10]
list1 = reorder_list(list1, [3,6,12,9])
print(list1)

為此,應該有一些列表理解能力:

碼:

def reorder_list(list_to_reorder, custom_order):
    new_list = [x for x in custom_order if x in set(list_to_reorder)]
    new_list.extend(x for x in list_to_reorder if x not in set(custom_order))
    return new_list

測試代碼:

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(reorder_list(list1, [9, 6, 3, 12]))

結果:

[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]
def reorder_list(items, early):
    moved = [item for item in early if item in items]
    remain = [item for item in items if item not in moved]
    return moved + remain

這實際上與Gireesh和Stephen Rauch編寫的算法相同。 Gireesh的版本按照列表理解之前的方式編寫,而Stephen則使用集合進行更快的查找(但將兩個輸入列表都轉換為集合;一個就足夠了),並使用生成器表達式擴展而不是分配第二個列表。

需要注意的一件事是,我們假設項目在列表中是唯一的。 無論inset想到這個。

00sdf0的答案使用了一種非常不同的算法,它具有惰性評估和尾部調用優化功能,這在Haskell中可能是有意義的,但在這種情況下,似乎既不容易理解也不高效。 使用slice可以更清楚地重寫它:

def reorder_list(items, early):
    result = list(items)
    for move in reversed(early):
        try:
            place = result.index(move)
            result = [result[place]] + result[:place] + result[place+1:]
        except ValueError:
            pass   # this item wasn't in the list

這確實分配了更多列表,有效地將每個移動項的列表復制兩次。 使用islice而不是slice產生的懶惰評估避免了那些副本之一。

可以使用itertools.chainitertools.islice以以下方式解決該問題。

from itertools import chain, islice

lst = [1,2,3,4,5,6,7,8,9,10]
items_to_move = [9,6,3,12]

# move index i to front of list
def front(seq, i):
    item = islice(seq, i, i+1)
    start = islice(seq, 0, i, None)
    end = islice(seq, i+1, None)
    return list(chain(item,start,end))    

for item in reversed(items_to_move):
    if item in lst:
        lst = front(lst, lst.index(item))

輸出:

[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]

暫無
暫無

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

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