Reputation: 1116
I have a list of strings and integers and want to sort the list, preserving the numbers like so
["Hello", 1, 2, "World", 6, "Foo", 3]
would become
["Foo", 1, 2, "Hello", 6, "World", 3]
In short, it only sorts the strings in the list, not the integers, which stay in place. I've tried using the key
parameter with list.sort()
but haven't managed to achieve what I want.
Can anyone help me with this?
EDIT: this is different to the linked question as I want to preserve the integers' indexes, rather than sort them along with the strings.
EDIT: this is different to the second linked question as answers from that question can solve the problem using the key
parameter, something I have explicitly stated does not work in this instance.
Upvotes: 5
Views: 760
Reputation: 78554
Picked up this cool trick from @JonClements the other day.
Here goes:
gen = iter(sorted([x for x in lst if isinstance(x, str)]))
new_lst = [next(gen) if isinstance(x, str) else x for x in lst]
print(new_lst)
# ['Foo', 1, 2, 'Hello', 6, 'World', 3]
Sort the strings separately and create a generator expression from the sorted strings. In a list comprehension, pick objects alternately from the gen. exp. using a ternary conditional if only the items in the original position is a string, otherwise, pick an item (an integer) from the initial list.
Upvotes: 15
Reputation: 3613
First you sort the array only with string in extracting it, then you replace the strings step by step in the original array :
l = ["Foo", 1, 2, "Hello", 6, "World", 3]
s = [x for x in l if type(x) == str]
s.sort()
j = 0
for i, x in enumerate(l):
if type(x) == str:
l[i] = s[j]
j += 1
Upvotes: 0
Reputation: 140256
First, sorting of an heterogenous list like this only works in Python 2. But the result is not what you need.
I would create a iterator on the sorted version of the filtered list (keeping only string) and rebuild the list with either an item of this iterator or the original list depending on the element type:
l = ["Hello", 1, 2, "World", 6, "Foo", 3]
sgen = iter(sorted([x for x in l if isinstance(x,str)]))
result = [next(sgen) if isinstance(x,str) else x for x in l]
print(result)
result:
['Foo', 1, 2, 'Hello', 6, 'World', 3]
Upvotes: 8