python: самый элегантный способ пересечения списка с элементом

Входные данные:

intersperse(666, ["once", "upon", "a", 90, None, "time"]) 

Вывод:

 ["once", 666, "upon", 666, "a", 666, 90, 666, None, 666, "time"] 

Какой из самых элегантных (читай: Pythonic) способ писать в нескольких intersperse ?

Я бы написал генератор сам, но вот так:

 def joinit(iterable, delimiter): it = iter(iterable) yield next(it) for x in it: yield delimiter yield x 

itertools на помощь
– или –
Сколько функций itertools вы можете использовать в одной строке?

 from itertools import chain, izip, repeat, islice def intersperse(delimiter, seq): return islice(chain.from_iterable(izip(repeat(delimiter), seq)), 1, None) 

Применение:

 >>> list(intersperse(666, ["once", "upon", "a", 90, None, "time"]) ["once", 666, "upon", 666, "a", 666, 90, 666, None, 666, "time"] 

Другой вариант, который работает для последовательностей:

 def intersperse(seq, value): res = [value] * (2 * len(seq) - 1) res[::2] = seq return res 

Я бы пошел с простым генератором.

 def intersperse(val, sequence): first = True for item in sequence: if not first: yield val yield item first = False 

и тогда вы можете получить свой список следующим образом:

 >>> list(intersperse(666, ["once", "upon", "a", 90, None, "time"])) ['once', 666, 'upon', 666, 'a', 666, 90, 666, None, 666, 'time'] 

вы также можете сделать:

 def intersperse(val, sequence): for i, item in enumerate(sequence): if i != 0: yield val yield item 

Я не уверен, что больше pythonic

 def intersperse(word,your_list): x = [j for i in your_list for j in [i,word]] >>> intersperse(666, ["once", "upon", "a", 90, None, "time"]) ['once', 666, 'upon', 666, 'a', 666, 90, 666, None, 666, 'time', 666] 

[Изменить] Исправленный код ниже:

 def intersperse(word,your_list): x = [j for i in your_list for j in [i,word]] x.pop() return x >>> intersperse(666, ["once", "upon", "a", 90, None, "time"]) ['once', 666, 'upon', 666, 'a', 666, 90, 666, None, 666, 'time'] 

Как насчет:

 from itertools import chain,izip_longest def intersperse(x,y): return list(chain(*izip_longest(x,[],fillvalue=y))) 

Dunno, если это pythonic, но это довольно просто:

 def intersperse(elem, list): result = [] for e in list: result.extend([e, elem]) return result[:-1] 

Это работает:

 >>> def intersperse(e, l): ... return reduce(lambda x,y: x+y, zip(l, [e]*len(l))) >>> intersperse(666, ["once", "upon", "a", 90, None, "time"]) ('once', 666, 'upon', 666, 'a', 666, 90, 666, None, 666, 'time', 666) 

Если вы не хотите отставать 666 , return reduce(...)[:-1] .

Я только что придумал это сейчас, googled, чтобы увидеть, есть ли что-то лучше … и ИМХО не было 🙂

 def intersperse(e, l): return list(itertools.chain(*[(i, e) for i in l]))[0:-1] 
 def intersperse(items, delim): i = iter(items) return reduce(lambda x, y: x + [delim, y], i, [i.next()]) 

Должен работать для списков или генераторов.