An effective and immutable way to turn two Python lists into one

23 June 2021   7 comments   Python

tl;dr; To make 2 lists into 1 without mutating them use list1 + list2.

I'm blogging about this because today I accidentally complicated my own code. From now on, let's just focus on the right way.

Suppose you have something like this:

winners = [123, 503, 1001]
losers = [45, 812, 332]

combined = winners + losers

that will create a brand new list. To prove that it's immutable:

>>> combined.insert(0, 100)
>>> combined
[100, 123, 503, 1001, 45, 812, 332]
>>> winners
[123, 503, 1001]
>>> losers
[45, 812, 332]

What I originally did was:

winners = [123, 503, 1001]
losers = [45, 812, 332]

combined = [*winners, *losers]

This works the same and that syntax feels very JavaScript'y. E.g.

> var winners = [123, 503, 1001]
[ 123, 503, 1001 ]
> var losers = [45, 812, 332]
[ 45, 812, 332 ]
> var combined = [...winners, ...losers]
[ 123, 503, 1001, 45, 812, 332 ]
> combined.pop()
332
> losers
[ 45, 812, 332 ]

By the way, if you want to filter out duplicates, do this:

>>> a = [1, 2, 3]
>>> b = [2, 3, 4]
>>> list(dict.fromkeys(a + b))
[1, 2, 3, 4]

It's the most performant way to do it if the order is important.

And if you don't care about the order you can use this:

>>> a = [1, 2, 3]
>>> b = [2, 3, 4]
>>> list(set(a + b))
[1, 2, 3, 4]
>>> list(set(b + a))
[1, 2, 3, 4]

Comments

ëRiC

I'd say "To prove that it's new:"! Btw: when mutating the list with `combined.insert(0, 100)` I get `[100, 123, 503, 1001, 45, 812, *332*]`

And isn't it "if you *want* to filter out duplicates", right?

Some good pieces! 👍

Peter Bengtsson

I updated the sample to reflect that bug. See comment from Phil below. Thank you you too for noticing!

Also, I corrected the typo with "want" on the topic of filtering out duplicates.

Phil Colbert

Ouch. Feel free to discard this post after you fix this.

After the insert, shouldn't combined be
[100, 123, 503, 1001, 45, 812, 332]
?
After all, you started with 2 lists of 3 items (6 total). Adding another item gives 7 items, not 6.

Peter Bengtsson

You are stunningly correct! Thanks for the catch. Bad copy-n-pasta-job on my end. Corrected and again, thank you for mentioning it.

Phil Colbert

Ouch again. Sorry to do this...

combined.insert(0, 100)

doesn't prove that anything is *im*mutable. Rather, it proves that "combined" is mutable.

Is your goal is to prove that subsequences "winners" and "losers" are not shared with "combined"? If so, then you need a different proof, e.g., alter a position in "combined" that "would" be shared.

Peter Bengtsson

Fair point! doing `combined.insert` was meant as an example of mutating the new list. You're right, it doesn't really prove that `winners` and `losers` are immutable. I just wanted to demonstrate that once `combined` has been created, and if you change it, it doesn't change the lists that were used to *create* the new list.

Phil Colbert

Yes. Alas, the term for that is not "immutable". "immutable" is an adjective, and applies to data structures, such as a tuple or frozenset. It is not an adverb, so it does not apply to actions, such as operators, or function calls. On a constructive note, perhaps the phrase you're looking for is "side-effect free".

As for the number of lists... You demonstrate that, after the concatenation, you really do have *three* lists, not one. I'm at a loss as to how to fix the title to reflect that.

Your email will never ever be published

Related posts