2

I am trying to reorder items in a list in a way illustrated by the following example:

Suppose the list before reordering is:

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

I want to implement a method called reorder_list(list, custom_order) such that:

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

Explanation: [3, 6, 12, 9] is a custom order I am specifying. 12 is not in list1 so it will be ignored. 3,6,9 are in list1, so they get moved to the front of the list and their order is the same as in [3, 6, 12, 9]. The remaining items in list1 are after 3,6,9 and in the original order.

Is there is an easier way (and a Pythonic way) than implementing the C-like loop code. For my purpose I care more about code simplicity than performance.

4 Answers 4

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 

This is really the same algorithm as Gireesh and Stephen Rauch wrote. Gireesh's version is written as it would be before list comprehensions, while Stephen's uses sets for faster lookups (but converts both input lists to sets; one should suffice) and extends with a generator expression instead of allocating a second list.

One thing of note is that we've assumed items are unique within the lists. Both in and set expect this.

00sdf0's answer uses a very different algorithm that might make sense in Haskell, with its lazy evaluation and tail call optimization, but in this case seems neither easily understood nor performant. It can be more clearly rewritten using slices:

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 

This does allocate more lists, effectively shallow copying the list twice per moved item. Using islice instead of slice produced lazy evaluation that avoided one of those copies.

Sign up to request clarification or add additional context in comments.

Comments

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) 

Comments

1

A couple of list comprehensions should be reasonably performant for this:

Code:

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 

Test Code:

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

Results:

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

Comments

0

The problem may be solved in the following way using itertools.chain and 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)) 

Output:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.