[Tutor] to place all zeros of an existing list in the starting of a new list
Roel Schroeven
roel at roelschroeven.net
Mon May 31 17:48:34 EDT 2021
Manprit Singh schreef op 31/05/2021 om 1:56:
> Consider a list ls = [2, 5, 0, 9, 0, 8], now i have to generate a new list
> from this existing list , new list must contain all zeros in the starting,
> all other elements of the existing list must be placed after zeros in new
> list . So new list must be :
> new = [0, 0, 2, 5, 9, 8]
>
> The way I am doing it is :
>>>> ls = [2, 5, 0, 9, 0, 8]
>>>> sorted(ls, key=lambda x: x != 0)
> [0, 0, 2, 5, 9, 8]
>>>>
> Is this the correct way ? or is there something better that can be done ?
First, a note about correctness:
Your approach is fine if the sort function you use is stable, meaning
that it doesn't change the relative order of elements that compare equal
(i.e. in this case: keep 2, 5, 9 and in the correct order). It just so
happens that Python's sorted() function, and the sort() method on lists,
are guaranteed to be stable, so your approach works just fine.
Just remember that that doesn't necessarily translate to other
environments. For example, std::sort() in C++ is *not* guaranteed to
preserve the order of equal elements (I know because I got bitten by
that some time ago). When you ever face a similar problem using another
sort function, be sure to read the documentation to find out if the sort
function is stable.
Secondly, an alternative approach, with different performance:
Python uses Timsort (so called because it's written by Python dev Tim
Peters); see https://en.wikipedia.org/wiki/Timsort. Timsort is pretty
efficient as sorting algorithms go; in fact it is adopted in the sorting
functions in other programming languages. Even so, it may be that
another approach may be faster.
You could do two passes over the original list: first to collect the
zeros, next to collect all the other numbers, and then put them all
together:
[n for n in ls if n == 0] + [n for n in ls if n != 0]
Or a variation that prevents building two possibly large temporary list
through the use of generator expressions and itertools.chain to combine
them:
from itertools import chain
list(chain((n for n in ls if n == 0), (n for n in ls if n != 0)))
The sorting approach has complexity O(n log n), my alternative has
complexity O(n). O(n) is better all else being equal, but simply
comparing the complexities isn't the whole story. It's very well
possible that my alternative has a high constant factor, meaning that is
slower for small lists and only gets faster than your approach for very
large lists.
I don't really think it's something to worry about, unless this is
something you are going to use in a time-sensitive situation with large
lists, in which case you should benchmark different approaches. Mainly I
just wanted to show you a possible alternative solution.
--
"Honest criticism is hard to take, particularly from a relative, a
friend, an acquaintance, or a stranger."
-- Franklin P. Jones
Roel Schroeven
More information about the Tutor
mailing list