Reputation: 1116
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
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
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
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
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