sam cammegh
sam cammegh

Reputation: 55

How can I have changes made to one list affect another, different list?

So, I have two lists which contain:

[10, 10, 2, 9, 10]
['Jem', 'Sam', 'Sam', 'Jem', 'Jem']

I want to sort the second list using the .sort() function, and I want the changes made to the second list to affect the first list, i.e.

['Jem', 'Jem', 'Jem', 'Sam', 'Sam']
[10, 9, 10, 10, 2]

If that wasn't clear, then think of it as the two lists being linked. The strings/integers at each point in the two lists ([0], [1] etc.) are joined together, so that every change to the position of an element of one list is reflected by an equal change in the position of the corresponding element in the other list. How would I achieve this?

Upvotes: 1

Views: 217

Answers (5)

Malik Brahimi
Malik Brahimi

Reputation: 16711

Just zip them together and sort by name:

name = ['Jem', 'Sam', 'Sam', 'Jem', 'Jem']
nums = [10, 10, 2, 9, 10]

sort = sorted(zip(name, nums), key = lambda i:i[0])

name = [i[0] for i in sort] # split name again
nums = [i[1] for i in sort] # split nums again

Upvotes: 0

Christopher Peterson
Christopher Peterson

Reputation: 1671

It's about time you were introduced to Python's zip!

And then you could use it like this:

def sorted_together(*args, **kwargs):
    reverse = False
    key = None
    if 'reverse' in kwargs:
        reverse = kwargs['reverse']
    if 'key' in kwargs:
        key = kwargs['key']
    zipped = zip(*args)
    zipped.sort(reverse=reverse, key=key)
    tups = zip(*zipped)
    lists = [list(x) for x in tups]    #
    return lists

Remember that zip() returns a list of tuples, so if you're looking to get lists back out at the end the last list comprehension is very necessary.

Upvotes: 1

NPE
NPE

Reputation: 500207

Here is one way to do it:

In [18]: l1 = [10, 10, 2, 9, 10]

In [19]: l2 = ['Jem', 'Sam', 'Sam', 'Jem', 'Jem']

In [20]: l2, _, l1 = map(list, zip(*sorted(zip(l2, range(len(l1)), l1))))

In [21]: l1
Out[21]: [10, 9, 10, 10, 2]

In [22]: l2
Out[22]: ['Jem', 'Jem', 'Jem', 'Sam', 'Sam']

From the inside out:

  • zip(l2, range(len(l1)), l1) produces a list of tuples like so:

    [('Jem', 0, 10), ('Jem', 1, 9), ('Jem', 2, 10), ('Sam', 3, 10), ('Sam', 4, 2)]

    Here, the first element is the item from l2, the second element is simply a counter starting from zero, and the third element is the item from l1.

  • sorted(...) sorts the tuples first by l2 and then by the position in the original list (I am guessing from your example that this is what you want; the code can be simplified if you have no such requirement).

  • zip(*...) splits the sorted list into a list of three tuples.

  • map(list, ...) converts the tuples to lists.

  • l2, _, l1 assigns the first and third lists to l2 and l1, and discards the second list.

Upvotes: 1

Cory Kramer
Cory Kramer

Reputation: 117856

If the lists are indeed correlated/related, I would zip them.

>>> l1 = [10, 10, 2, 9, 10]
>>> l2 = ['Jem', 'Sam', 'Sam', 'Jem', 'Jem']
>>> pairs = list(zip(l1,l2))
>>> pairs
[(10, 'Jem'), (10, 'Sam'), (2, 'Sam'), (9, 'Jem'), (10, 'Jem')]

Then you can sort them by the names or the values using the key argument of sort or sorted

>>> sorted(pairs, key = lambda i : i[1])
[(10, 'Jem'), (9, 'Jem'), (10, 'Jem'), (10, 'Sam'), (2, 'Sam')]

Upvotes: 1

Andy
Andy

Reputation: 50540

It may make sense to actually link your two lists into a list of tuples:

list_1 = [10, 10, 2, 9, 10]
list_2 = ['Jem', 'Sam', 'Sam', 'Jem', 'Jem']

merged_list = zip(list_1, list_2)
print sorted(merged_list, key=lambda x: x[1])

This prints out the following:

[(10, 'Jem'), (9, 'Jem'), (10, 'Jem'), (10, 'Sam'), (2, 'Sam')]

You can then unmerge these lists (into two separate tuples) if you need, otherwise you can operate on the list of tuples

unlinked = zip(*sorted_merged)
print unlinked

Outputs:

[(10, 9, 10, 10, 2), ('Jem', 'Jem', 'Jem', 'Sam', 'Sam')]

Upvotes: 1

Related Questions