Reputation: 62165
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
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
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
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
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
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
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
Reputation: 5717
You may want to look at itertools. Also, here's a tutorial on Python iterators and generators (pdf).
Upvotes: 0