I have a 2D list that looks like this:
table = [['donkey', '2', '1', '0'], ['goat', '5', '3', '2']]
I want to change the last three elements to integers, but the code below feels very ugly:
for row in table:
for i in range(len(row)-1):
row[i+1] = int(row[i+1])
But I'd rather have something that looks like:
for row in table:
for col in row[1:]:
col = int(col)
I think there should be a way to write the code above, but the slice creates an iterator/new list that's separate from the original, so the references don't carry over.
Is there some way to get a more Pythonic solution?
To add new values to the end of the nested list, use append() method. When you want to insert an item at a specific position in a nested list, use insert() method. You can merge one list into another by using extend() method.
A nested list is a list that appears as an element in another list. In this list, the element with index 3 is a nested list. If we print( nested[3] ), we get [10, 20] .
They're matrices (a list of rows, where each row is itself a list, or a list of columns where each column is itself a list). Lists are being used for what in other languages is known as structs, records, or tuples -- collections of data with a fixed structure.
Lists are useful data structures commonly used in Python programming. A nested list is a list of lists, or any list that has another list as an element (a sublist). They can be helpful if you want to create a matrix or need to store a sublist along with other data types.
for row in table: row[1:] = [int(c) for c in row[1:]]
Does above look more pythonic?
Try:
>>> for row in table: ... row[1:]=map(int,row[1:]) ... >>> table [['donkey', 2, 1, 0], ['goat', 5, 3, 2]]
AFAIK, assigning to a list
slice forces the operation to be done in place instead of creating a new list
.
I like Shekhar answer a lot.
As a general rule, when writing Python code, if you find yourself writing for i in range(len(somelist))
, you're doing it wrong:
enumerate
if you have a single listzip
or itertools.izip
if you have 2 or more lists you want to iterate on in parallelIn your case, the first column is different so you cannot elegantly use enumerate:
for row in table:
for i, val in enumerate(row):
if i == 0: continue
row[i] = int(val)
Your "ugly" code can be improved just by calling range
with two arguments:
for row in table:
for i in range(1, len(row)):
row[i] = int(row[i])
This is probably the best you can do if you insist on changing the items in place without allocating new temporary lists (either by using a list comprehension, map
, and/or slicing). See Is there an in-place equivalent to 'map' in python?
Although I don't recommend it, you can also make this code more general by introducing your own in-place map function:
def inplacemap(f, items, start=0, end=None):
"""Applies ``f`` to each item in the iterable ``items`` between the range
``start`` and ``end``."""
# If end was not specified, make it the length of the iterable
# We avoid setting end in the parameter list to force it to be evaluated on
# each invocation
if end is None:
end = len(items)
for i in range(start, end):
items[i] = f(items[i])
for row in table:
inplacemap(int, row, 1)
Personally, I find this less Pythonic. There is preferably only one obvious way to do it, and this isn't it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With