[Tutor] Ways of removing consequtive duplicates from a list

Peter Otten __peter__ at web.de
Mon Jul 18 04:25:19 EDT 2022


On 18/07/2022 05:34, dn wrote:
> On 17/07/2022 20.26, Peter Otten wrote:
>> On 17/07/2022 00:01, Alex Kleider wrote:
>>
>>> PS My (at least for me easier to comprehend) solution:
>>>
>>> def rm_duplicates(iterable):
>>>       last = ''
>>>       for item in iterable:
>>>           if item != last:
>>>               yield item
>>>               last = item
>>
>> The problem with this is the choice of the initial value for 'last':
>
> Remember "unpacking", eg

Try

first, *rest = itertools.count()

;)

If you want the full generality of the iterator-based approach unpacking
is right out.


>> Another fix is to yield the first item unconditionally:
>>
>> def rm_duplicates(iterable):
>>      it = iter(iterable)
>>      try:
>>          last = next(it)
>>      except StopIteration:
>>          return
>>      yield last
>>      for item in it:
>>          if item != last:
>>              yield item
>>              last = item
>>
>> If you think that this doesn't look very elegant you may join me in the
>> https://peps.python.org/pep-0479/ haters' club ;)

> This does indeed qualify as 'ugly'. However, it doesn't need to be
> expressed in such an ugly fashion!

On second thought, I'm not exception-shy, and compared to the other options

last = next(it, out_of_band)
if last is out_of_band: return

or

for last in it:
     break
else:
    return

I prefer the first version. I'd probably go with

[key for key, _value in groupby(items)]

though.

However, if you look at the Python equivalent to groupby()

https://docs.python.org/3/library/itertools.html#itertools.groupby

you'll find that this just means that the "ugly" parts have been written
by someone else. I generally like that strategy -- if you have an "ugly"
piece of code, stick it into a function with a clean interface, add some
tests to ensure it works as advertised, and move on.


More information about the Tutor mailing list