caird coinheringaahing
caird coinheringaahing

Reputation: 1116

How to sort a list, only sorting strings?

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

Answers (3)

Moses Koledoye
Moses Koledoye

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

glegoux
glegoux

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

Jean-François Fabre
Jean-François Fabre

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

Related Questions