Python - 通过将一些项目移到前面,同时将其余项目保持在相同的顺序,重新排序列表中的项目

时间:2017-11-16 04:02:19

标签: python algorithm python-3.x list-comprehension

我正尝试按照以下示例说明的方式重新排序列表中的项目:

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

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

我想实现一个名为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的循环代码更简单的方法(和Pythonic方式)。出于我的目的,我更关心代码简单而不是性能。

4 个答案:

答案 0 :(得分:1)

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)

答案 1 :(得分:1)

对于这一点,一些列表推导应该具有合理的性能:

代码:

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]

答案 2 :(得分:1)

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中有意义,具有懒惰的评估和尾调用优化,但在这种情况下似乎既不易理解也不高效。使用切片可以更清楚地重写:

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生成了懒惰的评估,避免了其中一个副本。

答案 3 :(得分:0)

可以使用--helpitertools.chain以下列方式解决问题。

itertools.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))