moswald
moswald

Reputation: 11677

Replacing list item with contents of another list

Similar to this question, but instead of replacing one item with another, I'd like to replace any occurrences of one item with the contents of a list.

orig = [ 'a', 'b', 'c', 'd', 'c' ]
repl = [ 'x', 'y', 'z' ]
desired = [ 'a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z' ]

# these are all incorrect, or fail to compile
[ repl if x == 'c' else x for x in orig ]
[ [a for a in orig] if x == 'c' else x for x in orig ]
[ (a for a in orig) if x == 'c' else x for x in orig ]
[ a for a in orig if x == 'c' else x for x in orig ]

Edit: made it clear I meant to replace all occurrences of the item, rather than just the first. (Apologies to anyone who didn't cover that case in their answer.)

Upvotes: 2

Views: 5959

Answers (5)

shantanoo
shantanoo

Reputation: 3704

Yet another way:

>>> import operator
>>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
>>> repl = [ 'x', 'y', 'z' ]
>>> output = [repl if x == 'c' else [x] for x in orig]
>>> reduce(operator.add, output)
['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']
>>> 

Upvotes: 0

tdelaney
tdelaney

Reputation: 77347

If you enumerate backwards, you can extend the list as you go because the items you move have already gone through the enumeration.

>>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
>>> repl = [ 'x', 'y', 'z' ]
>>> desired = [ 'a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z' ]
>>> for i in xrange(len(orig)-1, -1, -1):
...     if orig[i] == 'c':
...             orig[i:i+1] = repl
... 
>>> orig
['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']

Upvotes: 0

DSM
DSM

Reputation: 353059

Different approach: when I'm doing replacements, I prefer to think in terms of dictionaries. So I'd do something like

>>> orig = [ 'a', 'b', 'c', 'd' ]
>>> rep = {'c': ['x', 'y', 'z']}
>>> [i for c in orig for i in rep.get(c, [c])]
['a', 'b', 'x', 'y', 'z', 'd']

where the last line is the standard flattening idiom.

One advantage (disadvantage?) of this approach is that it'll handle multiple occurrences of 'c'.

[update:]

Or, if you prefer:

>>> from itertools import chain
>>> list(chain.from_iterable(rep.get(c, [c]) for c in orig))
['a', 'b', 'x', 'y', 'z', 'd']

On the revised test case:

>>> orig = [ 'a', 'b', 'c', 'd', 'c' ]
>>> rep = {'c': ['x', 'y', 'z']}
>>> list(chain.from_iterable(rep.get(c, [c]) for c in orig))
['a', 'b', 'x', 'y', 'z', 'd', 'x', 'y', 'z']

Upvotes: 4

mgilson
mgilson

Reputation: 309929

>>> orig = [ 'a', 'b', 'c', 'd' ]
>>> repl = [ 'x', 'y', 'z' ]
>>> desired = list(orig)  #can skip this and just use `orig` if you don't mind modifying it (and it is a list already)
>>> desired[2:3] = repl
>>> desired
['a', 'b', 'x', 'y', 'z', 'd']

And of course, if you don't know that 'c' is at index 2, you can use orig.index('c') to find out that information.

Upvotes: 6

JBernardo
JBernardo

Reputation: 33397

No need for anything fancy:

desired = orig[:2] + repl + orig[3:]

To find 2 you can search for orig.index('c').

x = orig.index('c')
desired = orig[:x] + repl + orig[x+1:]

if repl is not a list, just use list(repl)

Upvotes: 2

Related Questions