Zastanawiam się, jaki jest skuteczny sposób liczenia zduplikowanych numerów listy. Oto przykład: liczby = [5, 10,10,10, 15,15, 8,8,8,8] odpowiedź = [1,3,2,4] . To jest mój kod, który wymyśliłem... ...

0
kw3136 28 czerwiec 2021, 12:35

5 odpowiedzi

Najlepsza odpowiedź

Możesz to zrobić za pomocą wbudowanego groupby

>>> from itertools import groupby
>>> numbers = [5, 10,10,10, 15,15, 8,8,8,8]
>>> [len(list(g)) for k, g in groupby(numbers)]
[1, 3, 2, 4]

groupby(iterable, key=None) tworzy iterator, który zwraca kolejne klucze i grupy z elementu iteracyjnego (w tym przypadku numbers). Klucz to funkcja obliczająca wartość klucza dla każdego elementu. Jeśli nie określono lub jest None, klucz domyślnie jest funkcją tożsamości i zwraca element bez zmian.

9
BioGeek 28 czerwiec 2021, 09:44

Możesz to zrobić:

res = {d:numbers.count(d) for d in numbers}        
print (res)

Wynik:

{5: 1, 10: 3, 15: 2, 8: 4}    

                                                                                                
1
BioGeek 28 czerwiec 2021, 09:46

Możesz liczyć przez dict, np.

from collections import defaultdict

result = defaultdict(int)
numbers = [5, 10, 10, 10, 15, 15, 8, 8, 8, 8]
for n in numbers:
    result[n] += 1
print(list(result.values()))
1
Will 28 czerwiec 2021, 09:48

Możesz po prostu użyć OrderedDict, aby zachować taką kolejność wyników. Dzięki haszowaniu wartości będzie to szybkie.

from collections import OrderedDict
numbers = [5, 10, 10, 10, 15, 15, 8, 8, 8, 8]
answer = [1, 3, 2, 4]
result_map = OrderedDict()
for item in numbers:
    if item in result_map:
        result_map[item] += 1
    else:
        result_map[item] = 1
result = list(result_map.values())
print(result)

Przy okazji, jestem pewien, że twoja lista ma porządek, możesz to zrobić, aby być szybszym.

result = []
last_value = None
for item in numbers:
    if last_value == item:
        result[-1] += 1
    else:
        result.append(1)
        last_value = item
print(result)
1
Xu Qiushi 28 czerwiec 2021, 09:53

Porównanie mojej metody i kilku innych sugerowanych tutaj:

from itertools import groupby
import timeit
from collections import defaultdict


numbers = [5, 10,10,10, 15,15, 8,8,8,8]

def manual():
    count = 1
    previous = numbers[0]
    out = []
    for number in numbers[1:]:
        if number == previous:
            count += 1
        else:
            out.append(count)
            count = 1
            previous = number
    out.append(count)
    return out

def built_in():
    return [len(list(g)) for k, g in groupby(numbers)]

def dict_count():
    result = defaultdict(int)
    for n in numbers:
        result[n] += 1
    return list(result.values())

def henro_method():
    res = {d:numbers.count(d) for d in numbers}        
    return res

print("'Manual' method average time:", timeit.timeit(manual, number=10000))
print("Built-in 'itertools' method average time:", timeit.timeit(built_in, number=10000))
print("'dict_count' method average time:", timeit.timeit(dict_count, number=10000))
print("'henro_method' method average time:", timeit.timeit(henro_method, number=10000))

Wynik:

'Manual' method average time: 0.013817799999999998
Built-in 'itertools' method average time: 0.0379492
'dict_count' method average time: 0.06737080000000001
'henro_method' method average time: 0.08482129999999999

Jak dotąd manual() jest najlepszy, co mnie nie dziwi: to czas liniowy.

1
Ezra 28 czerwiec 2021, 09:55