caird coinheringaahing
caird coinheringaahing

Reputation: 1116

Sort a list with certain values staying in constant positions

I have a list of strings. I want to only sort values that meet a certain condition. Consider this list

['foo','bar','testa','python','java','abc']

and I only want to sort the values with an a in them. The result should look like this

['foo','abc','bar','python','java','testa']

The elements with a will change places appropriately, but the other elements retain their original positions.

I have absolutely no idea how to implement this, so I hope someone else does. Can someone show me how to do this?

Upvotes: 3

Views: 3661

Answers (5)

EsotericVoid
EsotericVoid

Reputation: 2576

y = sorted(w for w in x if 'a' in w)  # pick and sort only the elements with 'a'
x = [w if 'a' not in w else y.pop(0) for w in x]

The last line leaves word without an 'a' in them unchanged, while those with 'a' are picked progressively from the y list (that is already sorted)

EDIT: @MartijnPieters solution performs better, since it uses an iterator and won't use additional memory to store y.

y = iter(sorted(w for w in x if 'a' in w))  # create iterator, don't use memory
x = [w if 'a' not in w else next(y) for w in x]  # yield from iter instead of popping from a list

Since it looks like you need this algorithm to work with different condition, you could put this into a method:

x = ['foo','bar','testa','python','java','abc']

def conditional_sort(ls, f):
    y = iter(sorted(w for w in ls if f(w)))
    return [w if not f(w) else next(y) for w in ls]

conditional_sort(x, lambda w: 'a' in w)

The first parameter would be the list, the second one a function that takes a single parameter and returns a bool value.

Upvotes: 8

cristiam.chica
cristiam.chica

Reputation: 21

I just would use two additional lists to keep track of the indices of words with 'a' and to sorted the words:

L=['foo','bar','testa','python','java','abc']
M=[]
count=[]
for t in L:
    if 'a' in t:
        M.append(t)               #append both the word and the index
        count.append(L.index(t))
M=sorted(M)
for l in count:
    L[l]=M[count.index(l)]       
L

Probably is not very efficient but it works.

Upvotes: 0

Prune
Prune

Reputation: 77867

Find the elements with a; mark the positions and pull them out.

orig = ['foo','bar','testa','python','java','abc']
just_a = [str for str in orig if `a` in str]
mark = [`a` in str for str in orig]

This gives us

just_a = ['bar', 'testa', 'java', 'abc'] 
mark = [False, True, True, False, True, True]

Sort just_a; I'm sure you can do that. Now, build your result: where there's True in mark, take the next item in the sorted list; otherwise, take the original element.

result = []
for pos in range len(orig):
    if mark[pos]:
        result.append(sort_a.pop())
    else:
        result.append(orig[pos])

This can be done with much less code. Among other things, this last loop can be done with a list comprehension. This code merely clarifies the process.

Upvotes: 1

jacoblaw
jacoblaw

Reputation: 1283

This can definitely be simplified, but here's one way of doing it

def custom_sort(lst):
    sorted_list = [x for x in lst if 'a' in x] # get list of everything with an a in it
    sorted_list.sort() # sort this of elements containing a
    final_list = [] # make empty list, we will fill this with what we need
    sorted_counter = 0 # need a counter to keep track of what element containing a have been accounted for below
    for x in lst: # loop over original list
        if 'a' in x: # if that element in our original list contains an a
            final_list.append(sorted_list[sorted_counter]) # then we will from our sorted list of elements with a
            sorted_counter += 1 # increment counter
        else: # otherwise
            final_list.append(x) # we add an element from our original list
    return final_list # return the custom sorted list

Upvotes: 0

Lucas
Lucas

Reputation: 3

A possible approach would be to :

  1. Extract all values with an 'a' in them and note their positions.
  2. Sort the values alphabetically (see this post).
  3. Insert the sorted values into the original list.

Upvotes: 0

Related Questions