Search code examples
pythonfor-loopnestedlist-comprehensionnested-loops

Insert element in Python list after every other element list comprehension


The goal is to insert a string after every other element in the list apart from the last one:

arr0 = ['aa','bb','cc','dd']

Goal

 ['aa','XX','bb', 'XX','cc','XX','dd']

This topic has been addressed in posts like this, but the lists of strings used are only one character in length which affects the list comprehension. I do not have enough reputation points to comment and ask for clarification.

I have implemented it with a for loop, but I was trying to practice with list-comprehension and would appreciate insight as to where I am going wrong with it. Currently getting a SyntaxError: invalid syntax.

Example and Current Implementation

arr0 = ['aa','bb','cc','dd'] # Goal ['aa','XX','bb', 'XX','cc','XX','dd']

# Stop for range
total = len(arr0)*2-1

for i in range(1, total, 2):
   arr0.insert(i, "XX")

# Returns ['aa', 'XX', 'bb', 'XX', 'cc', 'XX', 'dd']

List Comprehension Attempt:

[el for y in [[el, 'XX'] if idx != len(arr0)-1 else el for idx, el in enumerate(arr0)] for el in y if isinstance(y, list) else el]
Breakdown
[[el, 'XX'] if idx != len(arr0)-1 else el for idx, el in enumerate(arr0)]

# Returns
# [['aa', 'XX'], ['bb', 'XX'], ['cc', 'XX'], 'dd']

In the outer comprehension, I am trying to return it as a single list of the strings. I am trying to use isinstance to check if the element is a list or not (the last item being a string) and if not return simply the string.

Edit

I really appreciate the responses. I should have included this alternative case that I do encounter where I do not want elements inserted after a 'Note' element at the end, in which case I could not perform the slice. Is negative indexing with a step possible?

# Alternative scenario
arr1 = ['aa','bb','cc','dd', 'Note']

# ['aa','XX,'bb','XX,'cc','XX,'dd','Note']

Solution

  • You can simply use a nested list comprehension and strip the last element:

    >>> [e for i in arr0 for e in [i, "XX"]][:-1]
    ['aa', 'XX', 'bb', 'XX', 'cc', 'XX', 'dd']
    

    You can also use a .split()/.join() trick (which is probably less performant):

    >>> ",XX,".join(arr0).split(",")
    ['aa', 'XX', 'bb', 'XX', 'cc', 'XX', 'dd']
    

    A fancier way is to use itertools.chain:

    >>> from itertools import chain
    >>> list(chain.from_iterable(zip(arr0, ["XX"]*len(arr0))))[:-1]
    ['aa', 'XX', 'bb', 'XX', 'cc', 'XX', 'dd']
    

    Edit: For the alternative case added later to the question, it is possible to slice the input and manually append the last element to the output:

    >>> arr1 = ['aa','bb','cc','dd', 'Note']
    >>> [e for i in arr1[:-1] for e in [i, "XX"]][:-1] + [arr1[-1]]
    ['aa', 'XX', 'bb', 'XX', 'cc', 'XX', 'dd', 'Note']