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
  • 12,464
  • 7
  • 65
  • 73

6 Answers6

8

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
  • 46,825
  • 13
  • 96
  • 126
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,827
  • 22
  • 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,611
  • 16
  • 25
3

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
  • 209,562
  • 33
  • 339
  • 356
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
  • 11,007
  • 2
  • 61
  • 75
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,820
  • 2
  • 28
  • 35