3

I have a structured list of lists in which each element is a string. I want to convert certain (known index, always the same) elements in this list of lists to integers. I've tried using list comprehension or the isdigit() method (there are no negative elements) but can't figure it out.

list_of_lists = [['spam','1','toast'], ['bacon','5','eggs'], ['juice', '8', 'tea']]
new_breakfast_list = [[int(element) for element in row] for row in list_of_lists]

The above code understandably gives ValueError: invalid literal for int() with base 10: 'spam' when it tries converting the first element. I want to either ignore the error and move forward to the next element or maybe specifically loop over something like list_of_lists[i][1] so I can get:

print(new_breakfast_list)
[['spam', 1, 'toast'], ['bacon', 5, 'eggs'], ['juice', 8, 'tea']]
3
  • 1
    What about using a list of dictionaries instead of a list of lists? Your inner elements seem to be structured, which would be more suitable to using a dictionary or even creating a class. Commented Feb 21, 2017 at 19:56
  • 1
    Is the element you want to convert always in the same position for each list? Commented Feb 21, 2017 at 20:05
  • Yes, using a class or a dictionary would probably be more suitable. Commented Feb 21, 2017 at 20:10

3 Answers 3

5

Your list comprehension is almost correct, you just need to check using isdigit() in the inner loop, and use int(element) or just element depending on the value if isdigit.

new_breakfast_list = [[int(element) for element in row if element.isdigit() else element] for row in list_of_lists]

Alternatively, as you know integer elements occur at index 1, you could use:

for element in list_of_lists:
    element[1]=int(element[1])

As you know the indexes you want to change, you should use this method as it saves needlessly looping through every element.

Sign up to request clarification or add additional context in comments.

5 Comments

Agree with this: If you know for sure that each inner list has 3 elements, then why loop over them...just index them. (Maybe that's not Pythonic?)
the for loop is maybe the simplest way to do it. Not every problem must be solved with list comprehension.
I was confused by that to call the correct element I needed a two-digit index e.g. print(list_of_lists[1]) gives ['bacon', 5, 'eggs'] not 5. If you write it like for row in list_of_lists: \n row[1]=int(row[1]) it makes more sense to me. Many thanks for the help!
Outside of the loop, you would need list_of_lists[x][1] to get the desired element as list_of_lists is 2-dimensional. However, in the loop, element is a list e.g on the first iteration, element would be ['spam', 1, 'toast']. As this is only a 1-dimensional list, you only need to index it using element[1]
Try new_lunch_list
2

since you're dealing with positive integers you can check if the string has only digits in it and convert or not using a ternary.

list_of_lists = [['spam','1','toast'], ['bacon','5','eggs'], ['juice', '8', 'tea']]
new_breakfast_list = [[int(element) if element.isdigit() else element for element in row] for row in list_of_lists]

yields:

[['spam', 1, 'toast'], ['bacon', 5, 'eggs'], ['juice', 8, 'tea']]

2 downsides though:

  • it tries to convert all items, even though only the 2nd one is an integer
  • it doesn't handle negatives (if you need them)

note: there's a cumbersome/not so performant way to handle the general positive/negative/starting with space integer case, use it only it you have to! otherwise the wim answer with try/except is better

new_breakfast_list = [[int(element) if element.strip().isdigit() or (element.strip()[0]=="-" and element.strip()[1:].isdigit()) else element for element in row] for row in list_of_lists]

4 Comments

isdigit is a bad way to check whether or not int(element) will work.
agreed but in that case you're dealing with number of elements, which cannot be negative, or I wouldn't have answered that.
OK, I missed that. Removed downvote.
fair enough. I know there is no easy way to deal with negative/positive in list comprehensions without making them overly complex...
1

Just define your own little helper function, something simple like:

def maybe_int(val):
    try:
        return int(val)
    except ValueError:
        return val

Now you can use that in any kind of comprehension you want. It will continue to work in some cases where using an str.isdigit check fails (e.g. whitespace in the string, negative numbers, etc).

If the structure of the data is reliable, don't bother with this stuff at all. Just do a simple list-comp:

>>> [[x, int(n), y] for x, n, y in list_of_lists]
[['spam', 1, 'toast'], ['bacon', 5, 'eggs'], ['juice', 8, 'tea']]

3 Comments

you should re-add the part about negative numbers. Most people overlook that part and your function looks cumbersome.
OK, added it back.
and your listcomp is good since it doesn't try to convert the other items.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.