2014-10-29 4 views
-4

У меня есть последовательность элементов, каждая из которых связана с ее весом w (положительное целое число) в кортеже. Что хорошего (предпочтительно, на основе итератора) создать последовательность или список, содержащий w_i экземпляров каждого элемента e_i?Создание нескольких копий элементов списка

weighted = [ ("a", 3), ("b", 1), ("c", 4) ] 

unrolled = [ "a", "a", "a", "b", "c", "c", "c", "c" ] 
+0

Я могу пощадить точки, но Мне любопытно, что думают, что ниспроверки ошибаются в этом вопросе. У него уже есть хорошие ответы. – alexis

+0

Я не голосовал, но вы не пытались решить проблему самостоятельно. –

ответ

2

Использования списка понимания с вложенным циклом:

unrolled = [c for c, count in weighted for _ in range(count)] 

Если вы используете Python 2, вы можете использовать вместо xrange().

Если вы хотите itertools, вы можете использовать itertools.chain.from_iterable(), чтобы сделать это в ленивой Iterable:

from itertools import chain 

chain.from_iterable([c] * count for c, count in weighted) 

Демо:

>>> weighted = [ ("a", 3), ("b", 1), ("c", 4) ] 
>>> [c for c, count in weighted for _ in range(count)] 
['a', 'a', 'a', 'b', 'c', 'c', 'c', 'c'] 
>>> from itertools import chain 
>>> list(chain.from_iterable([c] * count for c, count in weighted)) 
['a', 'a', 'a', 'b', 'c', 'c', 'c', 'c'] 

Я использовал list() превратить chain итератор в последовательность.

+0

Это было быстро! :-) – alexis

+0

Да, не знал об обязательном ожидании перед ответом. Хорошее дополнение, хотя я задаюсь вопросом, могут ли первые пользователи навсегда покинуть вас до того, как закончится 15 минут ... – alexis

0

Этот метод в основном создает одну строку с использованием выражения генератора и join, а затем превращает эту строку в list.

weighted = [ ("a", 3), ("b", 1), ("c", 4) ] 
unrolled = list(''.join([letter*count for letter,count in weighted])) 

>>> unrolled 
['a', 'a', 'a', 'b', 'c', 'c', 'c', 'c'] 
+0

Извините, но это поражает меня столь же круто и ограничивается (1) строками (2) одной буквы. С таким количеством выбора, зачем нужно умножать строки? – alexis

+0

Строки только что соответствовали прецеденту. Существует аналог для любой последовательности, однако, например, [3] * 3 является [3,3,3], поэтому вы можете использовать умножение последовательностей таким образом. В этом случае вместо 'join' вы просто используете' chain.from_iterable'. – CoryKramer

1

Counter имеет эту логику встроенная, предполагая, что порядок не важен

>>> weighted = [ ("a", 3), ("b", 1), ("c", 4) ] 
>>> from collections import Counter 
>>> c = Counter(dict(weighted)) 
>>> list(c.elements()) 
['a', 'a', 'a', 'c', 'c', 'c', 'c', 'b'] 

Другой способ с itertools (их много)

>>> from itertools import chain, repeat, starmap 
>>> list(chain.from_iterable(starmap(repeat, weighted))) 
['a', 'a', 'a', 'b', 'c', 'c', 'c', 'c'] 
+0

Ницца! Действительно, порядок не важен. (Решение «Counter» я имею в виду. «Itertools» - это слишком много сантехники, когда есть более простые решения). – alexis

+1

@alexis, я согласен. Я просто положил его туда, потому что я никогда не использовал «starmap» где-нибудь –

+0

Мне нравится подход «Counter», но я решил принять понимание, потому что он полагается на более известные функции python. – alexis

Смежные вопросы