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
Post your own commentI'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! 👍
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.
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.
You are stunningly correct! Thanks for the catch. Bad copy-n-pasta-job on my end. Corrected and again, thank you for mentioning it.
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.
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.
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.