heethesh
heethesh

Reputation: 401

Replacing duplicate elements in a list in Python?

For example if I have a list as follows:

[3, 3, 3, 3, 3, 3, 100, 1, 1, 1, 1, 1, 1, 200, 3, 3, 3, 100, 1, 1, 1]

How can I remove the duplicate elements and represent the same element followed by the number of times it's repeating? Example Output:

[3, 6, 100, 1, 6, 200, 3, 3, 100, 1, 3]

Where 3 is repeating 6 times... 1 repeating 6 times... and so on

Upvotes: 3

Views: 2840

Answers (4)

Kasravnd
Kasravnd

Reputation: 107287

As an alternative answer you can just play with indices using a recursion function and iter :

def refiner(li,new=[]):
     it=iter(li[1:])
     for i,j in enumerate(li[:-1],1):
            curr=next(it)
            if j!=curr :
                if i>1:
                  new+=[j,i]
                  return refiner(li[i:],new)

                elif i==len(li)-1:                  
                  new+=[j,curr]
                  return new

                else:
                    new+=[j]
                    return refiner(li[i:],new)

            elif i==len(li)-1:
                  new+=[j,i+1]
                  return new

     return new

DEMO:

l=[3, 3, 3, 3, 3, 3, 100, 1, 1, 1, 1, 1, 1, 200, 3, 3, 3, 100, 1, 1, 1]
print refiner(l)
[3, 6, 100, 1, 6, 200, 3, 3, 100, 1, 3]

l=[7, 7, 3, 9, 3, 3, 100, 1, 5, 1, 1, 1, 1, 200, 3, 3, 3, 100, 1, 7, 1]
print refiner(l)
[7, 2, 3, 9, 3, 2, 100, 1, 5, 1, 4, 200, 3, 3, 100, 1, 7, 1]

Upvotes: -1

Padraic Cunningham
Padraic Cunningham

Reputation: 180391

The itertools is the best solution but for a different take without imports we can use a dict:

od = {}

prev = None
out = []
for ele in l:
    if ele != prev and prev in od:
        out.extend((prev, od[prev])) if od[prev] > 1 else out.append(prev)
        od[prev] = 0
    od.setdefault(ele, 0)
    od[ele] += 1
    prev = ele
out.extend((ele, od[ele])) if od[ele] > 1 else out.append(ele)
print(out)
[3, 6, 100, 1, 6, 200, 3, 3, 100, 1, 3]

Or in a function using a more efficient defaultdict,it takes more memory to store data in a dict but it is probably a faster solution that using groupby:

def grp1(l):
    od = defaultdict(int)
    prev = None
    out = []
    for ele in l:
        if ele != prev and prev in od:
            out.extend((prev, od[prev])) if od[prev] > 1 else out.append(prev)
            od[prev] = 0
        od[ele] += 1
        prev = ele
    out.extend((ele, od[ele])) if od[ele] > 1 else out.append(ele)
    return out
[3, 6, 100, 1, 6, 200, 3, 3, 100, 1, 3]

Interestingly it is a nice amount faster, probably because we don't have to loop over every sublist to get the len :

In [33]: l = [choice(l) for _ in range(100000)]

In [34]: timeit grp1(l)
10 loops, best of 3: 23.9 ms per loop

In [35]: timeit list(solve(l))
10 loops, best of 3: 33.9 ms per loop

In [36]: list(solve(l)) == grp1(l)
Out[36]: True

Upvotes: 0

Dinara
Dinara

Reputation: 41

Alternative solution without using itertools would be:

my_list = [3, 3, 3, 3, 3, 3, 100, 1, 1, 1, 1, 1, 1, 200, 3, 3, 3, 100, 1, 1, 1]
new_list = []

new_list.append(my_list[0]) #adding first element

count = 1 #variable for counting repeated elements
i = 1 #iterator through list

l = len(my_list)

while i < l:
    while i < l and my_list[i] == my_list[i-1]:
        count +=1
        i+=1
    if count > 1:
        new_list.append(count)
        count = 1 #returning to original default value
    else:
        new_list.append(my_list[i])
        i+=1

print(new_list)

Upvotes: -1

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250891

You can use itertools.groupby with a generator function here:

>>> from itertools import groupby                                              
>>> lst = [3, 3, 3, 3, 3, 3, 100, 1, 1, 1, 1, 1, 1, 200, 3, 3, 3, 100, 1, 1, 1]
>>> def solve(seq):
    for k, g in groupby(seq):
        length = sum(1 for _ in g)
        if length > 1:
            yield k
            yield length
        else:
            yield  k
...             
>>> list(solve(lst))
[3, 6, 100, 1, 6, 200, 3, 3, 100, 1, 3]

Upvotes: 7

Related Questions