Efrat.shp
Efrat.shp

Reputation: 107

a program that compress a list.py

I'm trying to write a function which accepts a list of chars and return a list of tuples composed of the chars that were repetitive in the list and how many times they repeated. For example: if I have a list such as: ["a", "a", "b", "b", "b", "c", "a", "a"] It should return:

[('a', 2), ('b', 3), ('c', 1), ('a', 2)]

I wrote a code for this but the output I get is:

[('a', 2), ('b', 3), ('c', 1)]

Here is my code:

def comress(lst):
    i = 0
    counter = 0
    new_list = []
    while i < len(lst) -1:
        if lst[i] == lst[i+1]:
            counter += 1
            i += 1
        else:
            counter += 1
            tup = (lst[i], counter)
            new_list.append(tup)
            counter = 0
            i += 1

    return new_list
a = ["a", "a", "b", "b", "b", "c", "a", "a"]
print(comress(a))

I don't know what the problem is. I would like to hear your opinion. Thanks in advance.

Upvotes: 2

Views: 92

Answers (6)

Mike M&#252;ller
Mike M&#252;ller

Reputation: 85582

This is probably the most pythonic solution that uses your counter logic:

def comress(lst):
    counter = 1
    new_list = []
    for val1, val2 in zip(lst[:-1], lst[1:]):
        if val1 == val2:
            counter += 1
        else:
            new_list.append((val1, counter))
            counter = 1
    new_list.append((val2, counter))
    return new_list

​    
a = ["a", "a", "b", "b", "b", "c", "a", "a"]
print(comress(a))

Output:

[('a', 2), ('b', 3), ('c', 1), ('a', 2)]

Upvotes: 0

Mike M&#252;ller
Mike M&#252;ller

Reputation: 85582

You don't need to keep an extra counter, just increment the counter in the tuple if the value is the same as the previous one:

def compress(lst):
    res = [(lst[0], 1)]  #  take first value
    for val in lst[1:]:  #  go through the rest of the values
        if val == res[-1][0]:  #  if the value is the same as the last one in res
            res[-1] = (val, res[-1][-1] + 1)   #  increment the count
        else:   # otherwise
            res.append((val, 1))  #  add a new value-count pair
    return res

print(compress(lst))

Output:

[('a', 2), ('b', 3), ('c', 1), ('a', 2)]

Upvotes: 2

Mohammad Yusuf
Mohammad Yusuf

Reputation: 17074

One liner with collections.Counter() and itertools.groupby() methods.

from itertools import groupby
from collections import Counter

l1 = ["a", "a", "b", "b", "b", "c", "a", "a"]
print [Counter(g).items()[0] for _, g in groupby(l1)]

Output:

[('a', 2), ('b', 3), ('c', 1), ('a', 2)]

Upvotes: 2

TerryA
TerryA

Reputation: 60024

You can try using itertools.groupby:

from itertools import groupby
L = ["a", "a", "b", "b", "b", "c", "a", "a"]
newL = []
for k, g in groupby(L):
    tempL = list(g)
    newL.append((k, len(tempL)))

Upvotes: 1

omri_saadon
omri_saadon

Reputation: 10669

Your code does not insert into the list when it comes to the last items, if they are equal you don't insert them.

You need to check the last items as well, if they are equal so insert them as well, as in here:

lst= ["a", "a", "b", "b", "b", "c", "a", "a"]
def comress(lst):
    i = 0
    counter = 0
    new_list = []
    while i < len(lst) - 1:
        if lst[i] == lst[i+1]:
            counter += 1
            i += 1
        else:
            counter += 1
            tup = (lst[i], counter)
            new_list.append(tup)
            counter = 0
            i += 1
        if i + 1 == len(lst) and lst[i] == lst[i-1]:
            counter +=1
            tup = (lst[i], counter)
            new_list.append(tup)

    return new_list
a = ["a", "a", "b", "b", "b", "c", "a", "a"]
print(comress(a))

>>> [('a', 2), ('b', 3), ('c', 1), ('a', 2)]

Upvotes: 1

haggai_e
haggai_e

Reputation: 4820

Your code will only append to new_list when the current character is different from the previous one. When the list traversal ends though, it ignores the last streak of characters.

Upvotes: 1

Related Questions