3

I have a python script with this list:

blocks = [
  "item-1",
  "item-2",
  "item-3.0;item-3.1;item-3.2"
]

I have tried this:

for (i, block) in enumerate(blocks):
  if ";" in block:
    [blocks.insert(i, c) for c in block.split(";")]
  else:
    blocks.insert(i, block)

To get this:

blocks = [
  "item-1",
  "item-2",
  "item-3.0",
  "item-3.1",
  "item-3.2"
]

Unfortunately my code keeps overwriting the the elements in the list, and I'm left with this:

blocks = [
  "item-1",
  "item-2",
  "item-3.2"
]

How can I modify the script to allow me to split a string inside of a list and then insert the new sub-strings into the position of the original string without overwriting the other elements in the list?

Georgy
  • 9,972
  • 7
  • 57
  • 66

6 Answers6

6

You may achieve this via using nested list comprehension expression:

blocks = [
   "item-1",
   "item-2",
   "item-3.0;item-3.1;item-3.2"
]

my_list = [a for b in blocks for a in b.split(';')]

where content hold by my_list will be:

['item-1', 'item-2', 'item-3.0', 'item-3.1', 'item-3.2']
Moinuddin Quadri
  • 43,657
  • 11
  • 92
  • 117
5

split will return a list, you don't need to check if ';' is in the block:

In [34]: [ii.split(';') for ii in blocks]
Out[34]: [['item-1'], ['item-2'], ['item-3.0', 'item-3.1', 'item-3.2']]

So now the only thing you need is to add all the list together, with the function sum.

sum( [ii.split(';') for ii in blocks] ,  [])
Jblasco
  • 3,667
  • 21
  • 25
  • [`sum()` is not recommended for this.](https://stackoverflow.com/a/952946/4518341) You could use a [nested list comprehension](https://stackoverflow.com/a/952952/4518341) instead. – wjandrea Jul 04 '21 at 18:41
  • 1
    Agreed, for long lists, it would not be efficient. I find nested list comprehensions... difficult to comprehend :p – Jblasco Jul 05 '21 at 13:06
4

It would probably be easier to make a new list:

blocks = [
  "item-1",
  "item-2",
  "item-3.0;item-3.1;item-3.2"
]

new_blocks = []

for block in blocks:
    for c in block.split(";"):
        new_blocks.append(c)

 # new_blocks = ['item-1', 'item-2', 'item-3.0', 'item-3.1', 'item-3.2']
Greg Jennings
  • 1,506
  • 15
  • 24
2

You can create a new list to hold the results instead of modifying the original list while looping through it:

result = []
for block in blocks:
    result.extend(block.split(";"))

result
# ['item-1', 'item-2', 'item-3.0', 'item-3.1', 'item-3.2']

Inspired by @Jblasco's answer, you can also use chain:

from itertools import chain
list(chain.from_iterable(block.split(';') for block in blocks))

# ['item-1', 'item-2', 'item-3.0', 'item-3.1', 'item-3.2']
Psidom
  • 195,464
  • 25
  • 298
  • 322
0

in place editing of lists while iterating over it is not a good idea.

As the other answers say, make a new list. If you're into list comprehensions (and make your head explode a little), try this:

blocks = [
  "item-1",
  "item-2",
  "item-3.0;item-3.1;item-3.2"
]
[substr for block in blocks for substr in block.split(';')]
hansaplast
  • 10,004
  • 2
  • 50
  • 64
0
';'.join(blocks).split(';')

out:

['item-1', 'item-2', 'item-3.0', 'item-3.1', 'item-3.2']

Just join the list together and split again.

And in the Document, sum a list is not recommended:

For some use cases, there are good alternatives to sum(). The preferred, fast way to concatenate a sequence of strings is by calling ''.join(sequence). To add floating point values with extended precision, see math.fsum(). To concatenate a series of iterables, consider using itertools.chain().

宏杰李
  • 11,204
  • 2
  • 24
  • 33