繁体   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