helpermethod
helpermethod

Reputation: 62165

A cleaner/shorter way to solve this problem?

This exercise is taken from Google's Python Class:

D. Given a list of numbers, return a list where all adjacent == elements have been reduced to a single element, so [1, 2, 2, 3] returns [1, 2, 3]. You may create a new list or modify the passed in list.

Here's my solution so far:

def remove_adjacent(nums):
  if not nums:
    return nums

  list = [nums[0]]

  for num in nums[1:]:
    if num != list[-1]:
        list.append(num)

  return list

But this looks more like a C program than a Python script, and I have a feeling this can be done much more elegant.

EDIT

So [1, 2, 2, 3] should give [1, 2, 3] and [1, 2, 3, 3, 2] should give [1, 2, 3, 2]

Upvotes: 3

Views: 325

Answers (7)

Jochen Ritzel
Jochen Ritzel

Reputation: 107608

There is function in itertools that works here:

import itertools
[key for key,seq in itertools.groupby([1,1,1,2,2,3,4,4])]

You can also write a generator:

def remove_adjacent(items):
    # iterate the items
    it = iter(items)
    # get the first one
    last = next(it)
    # yield it in any case
    yield last
    for current in it:
        # if the next item is different yield it
        if current != last:
            yield current
            last = current
        # else: its a duplicate, do nothing with it

print list(remove_adjacent([1,1,1,2,2,3,4,4]))

Upvotes: 9

Jessica
Jessica

Reputation: 6957

This is also somewhat functional; it could be written as a one-liner using lambdas but that would just make it more confusing. In Python 3 you'd need to import reduce from functools.

def remove_adjacent(nums):
  def maybe_append(l, x):
    return l + ([] if len(l) and l[-1] == x else [x])
  return reduce(maybe_append, nums, [])

Upvotes: 0

Tim Pietzcker
Tim Pietzcker

Reputation: 336138

This works, but I'm not quite happy with it yet because of the +[None] bit to ensure that the last element is also returned...

>>> mylist=[1,2,2,3,3,3,3,4,5,5,5]
>>> [x for x, y in zip(mylist, mylist[1:]+[None]) if x != y]
[1, 2, 3, 4, 5]

The most Pythonic way is probably to go the path of least resistance and use itertools.groupby() as suggested by THC4K and be done with it.

Upvotes: 2

kurosch
kurosch

Reputation: 2312

>>> def collapse( data ):
...  return list(sorted(set(data)))
... 
>>> collapse([1,2,2,3])
[1, 2, 3]

Second attempt after the additional requirment was added:

>>> def remove_adjacent( data ):
...     last = None
...     for datum in data:
...         if datum != last:
...             last = datum
...             yield datum
...             
>>> list( remove_adjacent( [1,2,2,3,2] ) )
[1, 2, 3, 2]

Upvotes: 1

James Broadhead
James Broadhead

Reputation: 1958

Solution using list comprehensions, zipping then iterating through a twice. Inefficient, but short and sweet. It also has the problem of extending a[1:] with something.

a = [ 1,2,2,2,3,4,4,5,3,3 ]

b = [ i for i,j in zip(a,a[1:] + [None]) if not i == j ]

Upvotes: 3

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798616

itertools to the rescue.

import itertools

def remove_adjacent(lst):
  i = iter(lst)
  yield next(i)
  for x, y in itertools.izip(lst, i):
    if x != y:
      yield y


L = [1, 2, 2, 3]

print list(remove_adjacent(L))

Upvotes: 3

Joseph Weissman
Joseph Weissman

Reputation: 5717

You may want to look at itertools. Also, here's a tutorial on Python iterators and generators (pdf).

Upvotes: 0

Related Questions