5
\$\begingroup\$

I want to place an element alternatively between any two elements of a list.

l1 = list('abcde')
fill = 'z'

How it should look like:

['a', 'z', 'b', 'z', 'c', 'z', 'd', 'z', 'e']

My solution:

fill = 'z'
l2 = [fill]*(len(l1)-1)
[x for t in map(None, l1, l2) for x in t if x]

Is there a better approach, i.e. that doesn't need to create another list?

\$\endgroup\$
5
\$\begingroup\$

if x will cause your code to break if any element of l1 is falsy (e.g. None, 0, or an empty string).

map(None, …) is a bit unusual. Usually, that would be handled by some kind of "zip" — either the zip() builtin function, or one of the zip functions in itertools.

If you are going to use list comprehensions, then you might as well go all the way and not use map() at all.

[element for item in l1 for element in (item, fill)][:-1]
\$\endgroup\$
7
\$\begingroup\$

What if fill were a comma? Does that remind you of a common string-handling idiom?

>>> ','.join('abcde')
'a,b,c,d,e'

The only remaining task is to convert that result into a list.

Therefore, the solution would be better written as:

list(fill.join(l1))
\$\endgroup\$
5
  • 1
    \$\begingroup\$ This only holds as long as fill is just one character. \$\endgroup\$
    – MERose
    Dec 25 '15 at 16:28
  • 4
    \$\begingroup\$ Why didn't you give a better example? Better yet, why don't you ask a less hypothetical question that represents your concrete application? \$\endgroup\$ Dec 25 '15 at 16:30
  • 1
    \$\begingroup\$ @MERose join works for multichar strings too \$\endgroup\$
    – Caridorc
    Dec 25 '15 at 16:54
  • 1
    \$\begingroup\$ @Caridorc But the fill would get split into multiple elements in the result. \$\endgroup\$ Dec 25 '15 at 16:56
  • 1
    \$\begingroup\$ @200_success: I'm not saying your solution is not working nor that it doesn't answer my question. I am just noting restrictions to your answer for further reference. \$\endgroup\$
    – MERose
    Dec 25 '15 at 18:01
4
\$\begingroup\$

map(None, ...) is deprecated and removed in Python 3, so it should be avoided (favour zip). Plus, you should really be ziping over a generator, like

from itertools import repeat

def interleave(sep, elems):
    ret = (elem for pair in zip(repeat(sep), elems) for elem in pair)
    next(ret, None)
    return ret

Use itertools.izip on Python 2.

Personally, I would much prefer this written out in long as

def interleave(sep, elems):
    def generate():
        for elem in elems:
            yield sep
            yield elem

    ret = generate()
    next(ret, None)
    return ret
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.