0

I have the following code that I want to write as list comprehension:

word = "in_str"
listc=[]
for i in range(len(list(word))):
    x = []
    x.append(i+1)
    x.append(list(word)[i])
    listc.append(x)
print(listc, end="\n")

How do I treat the multiple lines in the body? Basically, I want to transform my "in_str" into the following:

[[1, 'i'], [2, 'n'], [3, '_'], [4, 's'], [5, 't'], [6, 'r']]
codeforester
  • 39,467
  • 16
  • 112
  • 140
rororo
  • 815
  • 16
  • 31

4 Answers4

4

How do I treat the multiple lines in the body

By simplifying the expression down; you don't need multiple statements to build the nested list:

[i + 1, list(word)[i]]

gives you the same result as declaring x = [] and appending two the results of two expressions.

That would make the list comprehension

[
    [i + 1, list(word)[i]]
    for i in range(len(list(word)))
]

Next, you don't need to call list(word) to get the length of a string or to address individual characters. Strings are already sequences, so len(word) and word[i] also work:

[
    [i + 1, word[i]]
    for i in range(len(word))
]

Next, if you used the enumerate() function, you can generate both a running index to replace the range() loop, and get access to the individual characters of word without having to index; you can start the running index at 1 with a second argument to enumerate() (the default is to start at 0):

[[i, char] for i, char in enumerate(word, 1)]

If you don't have to have a list for each pair, just use enumerate(word, 1) directly in loops and get tuples:

list(enumerate(word, 1))

Demo:

>>> word = "in_str"
>>> list(enumerate(word, 1))
[(1, 'i'), (2, 'n'), (3, '_'), (4, 's'), (5, 't'), (6, 'r')]
>>> [[i, char] for i, char in enumerate(word, 1)]
[[1, 'i'], [2, 'n'], [3, '_'], [4, 's'], [5, 't'], [6, 'r']]
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
3

Please try this line:

[(i + 1, l) for i, l in enumerate(word)]

Or with lists:

[[i + 1, l] for i, l in enumerate(word)]

or a version from the comments (by @tobias_k):

list(enumerate(word, start=1))
Oleksandr Dashkov
  • 2,249
  • 1
  • 15
  • 29
2

I would do as such;

new_list = [list(x) for x in enumerate(word)]

this gives;

[[0, 'i'], [1, 'n'], [2, '_'], [3, 's'], [4, 't'], [5, 'r']]

EDIT: I see @Chris_Rands beat me to the punch, put it as an answer good sir!

Nordle
  • 2,915
  • 3
  • 16
  • 34
  • Thanks! I changed to `list(x+1)` so the index starts at 1 – rororo Oct 08 '18 at 12:19
  • @rororo `list(x+1)` does not work, `x` is a tuple, but you can use the `start=1` parameter of `enumerate` – tobias_k Oct 08 '18 at 12:19
  • can I also use `zip()` for this task? – rororo Oct 08 '18 at 12:21
  • @rororo You _could_ use `zip` and a `range`, but why bother? `enumerate` already does that for you. – PM 2Ring Oct 08 '18 at 12:22
  • @rororo: why complicate matters with `zip()`? `enumerate(word, start)` is essentially `zip(itertools.count(start), word)`, but using the latter only causes confusion for future readers of the code, including whomever chose to use the obscure version over the standard library function. – Martijn Pieters Oct 08 '18 at 19:18
2

You have a varitey options with this one, and more that arent listed

l = [[idx, item] for idx, item in enumerate(word, 1)]

l = list(map(list, enumerate(word, 1)))

l = list(map(list, zip(range(1, len(word)+1), word)))

l = []
for idx, item in enumerate(word, 1):
    l.append([idx, item])

# [[1, 'i'], [2, 'n'], [3, '_'], [4, 's'], [5, 't'], [6, 'r']]
vash_the_stampede
  • 4,590
  • 1
  • 8
  • 20
  • @MartijnPieters I agree with your stance on the enumerate zip combo and took that down, I left one zip example just based on the OP questioning about the zip procedures for this, thank your for help refining this answer – vash_the_stampede Oct 08 '18 at 19:18
  • You could take a look at [my answer on `enumerate()`](https://stackoverflow.com/questions/22171558/what-does-enumerate-mean/22171593#22171593); `range()` is much more verbose an object here than is needed to re-create `enumerate()`. – Martijn Pieters Oct 08 '18 at 20:24