is something like this
def mymethod():
return [[1,2,3,4],
[1,2,3,4],
[1,2,3,4],
[1,2,3,4]]
mylist = mymethod()
for _, thing, _, _ in mylist:
print thing
# this bit is meant to be outside the for loop,
# I mean it to represent the last value thing was in the for
if thing:
print thing
what I want to do is avoid the dummy variables, is there a smarter way to do this than
for thing in mylist:
print thing[1]
because then i would have to use thing[1]
any other time I needed it, without assigning it to a new variable and then things are just getting messy.
newish to python so sorry if I'm missing something obvious
Use the zip() Function to Iterate Over Two Lists in Python Python zip function enables us to iterate over two or more lists by running until the smaller list gets exhausted.
To get every other element in a Python list you can use the slice operator and use the fact that this operator allows to provide a step argument (with its extended syntax). Another approach is to use the mathematical concept of remainder and apply it to list indexes.
In Python, we can loop over list elements with for and while statements, and list comprehensions.
Use the append() method to add elements to a list while iterating over the list. Means you can add item in the list using loop and append method.
You could hack a generator expression
def mymethod():
return [[1,2,3,4],
[1,2,3,4],
[1,2,3,4],
[1,2,3,4]]
mylist = mymethod()
for thing in (i[1] for i in mylist):
print thing
# this bit is meant to be outside the for loop,
# I mean it to represent the last value thing was in the for
if thing:
print thing
If you want to get the second column of an array, you could use a list comprehension, like so:
a = [ [ 1, 2, 3, 4 ],
[ 5, 6, 7, 8 ],
[ 9,10,11,12 ],
[13,14,15,16 ] ]
second_column = [ row[1] for row in a ]
# you get [2, 6, 10, 14]
You can wrap this up in a function:
def get_column ( array, column_number ):
try:
return [row[column_number] for row in array]
except IndexError:
print ("Not enough columns!")
raise # Raise the exception again as we haven't dealt with the issue.
fourth_column = get_column(a,3)
# you get [4, 8, 12, 16]
tenth_column = get_column(a,9)
# You requested the tenth column of a 4-column array, so you get the "not enough columns!" message.
Though really, if you're working with rectangular arrays of numbers, you want to be using numpy
arrays, not lists of lists of numbers.
Or, by Lattyware's implied request, a generator version:
def column_iterator ( array, column_number ):
try:
for row in array:
yield row[column_number]
except IndexError:
print ("Not enough columns!")
raise
Usage is just like a normal list:
>>> for item in column_iterator(a,1):
... print(item)
...
2
6
10
14
>>>
The generator-nature is evident by:
>>> b = column_iterator(a,1)
>>> b.next()
2
>>> b.next()
6
>>> b.next()
10
>>> b.next()
14
Definitely, when would itertools.chain and slicing come into help?
for thing in itertools.islice(itertools.chain(*mylist),1,None,len(mylist)):
print(thing)
Numpy is also helpful for column slicing. Here is another example in numpy
for thing in numpy.array(mylist)[:,1]:
print(thing)
While I like Dikei's answer for clarity and terseness, I still believe that a good option is simply:
for sublist in mylist:
item = sublist[1]
...
do_stuff(item)
...
do_other_stuff(item)
...
It remains clear, can be expanded to do more easily, and is probably the fastest.
Here are some quick tests - I'm not sure about how accurate they will be thanks to doing nothing in the loop, but they probably give an idea:
python -m timeit -s "mylist = [range(1,8) for _ in range(1,8)]" 'for thing in mylist:' ' item=thing[1]' ' pass'
1000000 loops, best of 3: 1.25 usec per loop
python -m timeit -s "mylist = [range(1,8) for _ in range(1,8)]" 'for thing in (i[1] for i in mylist):' ' pass'
100000 loops, best of 3: 2.37 usec per loop
python -m timeit -s "mylist = [range(1,8) for _ in range(1,8)]" 'for thing in itertools.islice(itertools.chain(*mylist),1,None,len(mylist)):' ' pass'
1000000 loops, best of 3: 2.21 usec per loop
python -m timeit -s "import numpy" -s "mylist = numpy.array([range(1,8) for _ in range(1,8)])" 'for thing in mylist[:,1]:' ' pass'
1000000 loops, best of 3: 1.7 usec per loop
python -m timeit -s "import numpy" -s "mylist = [range(1,8) for _ in range(1,8)]" 'for thing in numpy.array(mylist)[:,1]:' ' pass'
10000 loops, best of 3: 63.8 usec per loop
Note that numpy is fast if once generated, but very slow to generate on demand for a single operation.
On large lists:
python -m timeit -s "mylist = [range(1,100) for _ in range(1,100)]" 'for thing in mylist:' ' item=thing[1]' ' pass'
100000 loops, best of 3: 16.3 usec per loop
python -m timeit -s "mylist = [range(1,100) for _ in range(1,100)]" 'for thing in (i[1] for i in mylist):' ' pass'
10000 loops, best of 3: 27 usec per loop
python -m timeit -s "mylist = [range(1,100) for _ in range(1,100)]" 'for thing in itertools.islice(itertools.chain(*mylist),1,None,len(mylist)):' ' pass'
10000 loops, best of 3: 101 usec per loop
python -m timeit -s "import numpy" -s "mylist = numpy.array([range(1,100) for _ in range(1,100)])" 'for thing in mylist[:,1]:' ' pass'
100000 loops, best of 3: 8.47 usec per loop
python -m timeit -s "import numpy" -s "mylist = [range(1,100) for _ in range(1,100)]" 'for thing in numpy.array(mylist)[:,1]:' ' pass'
100 loops, best of 3: 3.82 msec per loop
Remember that speed should always come second to readability, unless you really need it.
The method itemgetter()
can be used to solve this:
from operator import itemgetter
def mymethod():
return [[1,2,3,4],
[1,2,3,4],
[1,2,3,4],
[1,2,3,4]]
mylist = mymethod()
row = map(itemgetter(2), mylist)
print("row %s" % row)
thing = row[-1]
# this bit is meant to be outside the for loop,
# I mean it to represent the last value thing was in the for
if thing:
print thing
The output is:
row [3, 3, 3, 3]
3
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