For Loops and Iterating Through Lists

Ways to iterate over a list in Java

The three forms of looping are nearly identical. The enhanced for loop:

for (E element : list) {
. . .
}

is, according to the Java Language Specification, identical in effect to the explicit use of an iterator with a traditional for loop. In the third case, you can only modify the list contents by removing the current element and, then, only if you do it through the remove method of the iterator itself. With index-based iteration, you are free to modify the list in any way. However, adding or removing elements that come before the current index risks having your loop skipping elements or processing the same element multiple times; you need to adjust the loop index properly when you make such changes.

In all cases, element is a reference to the actual list element. None of the iteration methods makes a copy of anything in the list. Changes to the internal state of element will always be seen in the internal state of the corresponding element on the list.

Essentially, there are only two ways to iterate over a list: by using an index or by using an iterator. The enhanced for loop is just a syntactic shortcut introduced in Java 5 to avoid the tedium of explicitly defining an iterator. For both styles, you can come up with essentially trivial variations using for, while or do while blocks, but they all boil down to the same thing (or, rather, two things).

EDIT: As @iX3 points out in a comment, you can use a ListIterator to set the current element of a list as you are iterating. You would need to use List#listIterator() instead of List#iterator() to initialize the loop variable (which, obviously, would have to be declared a ListIterator rather than an Iterator).

for loops and iterating through lists

What's happening here is a list is mutated during looping.

Let's consider following code snippet:

a = [0, 1, 2, 3]
for a[-1] in a:
print a

Output is:

[0, 1, 2, 0]
[0, 1, 2, 1]
[0, 1, 2, 2]
[0, 1, 2, 2]

Each iteration:

  • reads value from position currently pointed by internal pointer
  • immediately assigns it to last element in list
  • after that last element is printed on standard output

So it goes like:

  • internal pointer points to first element, it's 0, and last element is overwritten with that value; list is [0, 1, 2, 0]; printed value is 0
  • internal pointer points to second element, it's 1, and last element is overwritten with that value; list is [0, 1, 2, 1]; printed value is 1
  • (...)
  • at last step, internal pointer points to last element; last element is overwritten by itself - list does not change on last iteration; printed element also does not change.

Iterate through list using for-loop while adding numbers

With a for-in loop, you iterate over the list's elements, not its indexes. I.e.:

for i in numbers:
convert = tomtoCm(i)
print(convert)

Having said that, the more idiomatic approach would probably be to use a list comprehension:

updated_list = [tomtoCm(i) for i in numbers]
print(updated_list)

Iterating through list of lists of lists

I think you want to print the nth sub-sublists consecutively from each sublist. You could unpack and zip a to get an iterable of tuples, then print each pair in them:

for tpl in zip(*a):
for pair in tpl:
print(pair)

Output:

[0, 0]
[1, 0]
[2, 0]
[3, 0]
[4, 0]
[6, 0]

Iterating Through List of Lists, Maintaining List Structure

Use a nested list comprehension, as below:

names = [['Matt', 'Matt', 'Paul'], ['Matt']]
res = [[name for name in lst if name == "Matt"] for lst in names]
print(res)

Output

[['Matt', 'Matt'], ['Matt']]

The above nested list comprehension is equivalent to the following for-loop:

res = []
for lst in names:
res.append([name for name in lst if name == "Matt"])
print(res)

A third alternative functional alternative using filter and partial, is to do:

from operator import eq
from functools import partial

names = [['Matt', 'Matt', 'Paul'], ['Matt']]

eq_matt = partial(eq, "Matt")
res = [[*filter(eq_matt, lst)] for lst in names]
print(res)

Micro-Benchmark

%timeit [[*filter(eq_matt, lst)] for lst in names]
56.3 µs ± 519 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit [[name for name in lst if "Matt" == name] for lst in names]
26.9 µs ± 355 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Setup (of micro-benchmarks)

import random
population = ["Matt", "James", "William", "Charles", "Paul", "John"]
names = [random.choices(population, k=10) for _ in range(50)]

Full Benchmark

Candidates

def nested_list_comprehension(names, needle="Matt"):
return [[name for name in lst if needle == name] for lst in names]

def functional_approach(names, needle="Matt"):
eq_matt = partial(eq, needle)
return [[*filter(eq_matt, lst)] for lst in names]

def count_approach(names, needle="Matt"):
return [[needle] * name.count(needle) for name in names]

Plot
Plot of alternative solutions

The above results were obtained for a list that varies from 100 to 1000 elements where each element is a list of 10 strings chosen at random from a population of 14 strings (names). The code for reproducing the results can be found here.
As it can be seen from the plot the most performant solution is the one from @rv.kvetch.

how to loop through each element in list and increment by one

Note that there is a built-in function sum() in Python that does that job probably better than any code you can write in Python.

sum([0, 1, 3, 6, 10])

However, if you want to practice writing your sum function by iterating through a list and summing all the elements, this is how you do it.

def my_sum(ls):
result = 0
for i in range(len(ls)):
result += ls[i]
return result

First of all, you need to initialize a variable to hold your result. The range() function generates all values from 0 to x. The for-loop assigns all values generated by the range function to i in order and executes the indented block below. The += assignment increments the left-hand side variable by the right-hand side expression value. At last, we return the result.

And if you prefer using a while-loop,

def my_sum(ls):
result = 0
i = 0
while i < len(ls):
result += ls[i]
i += 1
return result

It's always good to consult Python documentation when you are not sure how to use its built-in function.

If you want the accumulated sum of all items reversed, you can take a look at the accumulate function in itertools.

from itertools import accumulate
def parts_sums(ls):
return list(accumulate(ls[::-1]))[::-1] + [0]

Or if you want to implement with a loop,

def parts_sums(ls):
result = []
part_sum = 0
for item in ls[::-1]:
result.append(part_sum)
part_sum += item
result.append(part_sum)

return result[::-1]

Or if you want to do it without reversing the list (say if you want to yield the results)

def parts_sums(ls):
result = []
part_sum = sum(ls)
for item in ls:
result.append(part_sum)
part_sum -= item
result.append(part_sum)

return result

Note the algorithm is still O(n), not that time complexity matters in this case.

Using Try Except to iterate through a list in Python

As stated, the try/except will work in that it will try the code under the try block. If at any point within that block it fails or raises and exception/error, it goes and executes the block of code under the except.

There are better ways to go about this problem (for example, I'd use BeautifulSoup to simply check the html for the "QB" position), but since you are a beginner, I think trying to learn this process will help you understand the loops.

So what this code does:

  • 1 It formats your player name into the link format.
  • 2 We initialize a while loop that will it will enter
  • 3 It gets the table.
  • 4a) It enters a function that checks if the table contains 'passing'
    stats by looking at the column headers.
  • 4b) If it finds 'passing' in the column, it will return a True statement to indicate it is a "QB" type of table (keep in mind sometimes there might be runningbacks or other positions who have passing stats, but we'll ignore that). If it returns True, the while loop will stop and go to the next name in your test list
  • 4c) If it returns False, it'll increment your name_int and check the next one
  • 5 To take care of a case where it never finds a QB table, the while loop will go to False if it tries 10 iterations

Code:

import pandas as pd

def check_stats(q_b1):
for col in q_b1.columns:
if 'passing' in col.lower():
return True
return False

test = ['Josh Allen', 'Lamar Jackson', 'Derek Carr']

empty_list=[]
for names in test:
name_int = 0
q_b_name = names.split()
link1=q_b_name[1][0].capitalize()

qbStatsInTable = False
while qbStatsInTable == False:
link2=q_b_name[1][0:4].capitalize()+q_b_name[0][0:2].capitalize()+f'0{name_int}'
url = f'https://www.pro-football-reference.com/players/{link1}/{link2}/gamelog/'

try:
q_b = pd.read_html(url, header=0)
q_b1 = q_b[0]
except Exception as e:
print(e)
break


#Check if "passing" in the table columns
qbStatsInTable = check_stats(q_b1)

if qbStatsInTable == True:
print(f'{names} - Found QB Stats in {link1}/{link2}/gamelog/')
empty_list.append(f'https://www.pro-football-reference.com/players/{link1}/{link2}/gamelog/')
else:
name_int += 1

if name_int == 10:
print(f'Did not find a link for {names}')
qbStatsInTable = False

Output:

print(empty_list)
['https://www.pro-football-reference.com/players/A/AlleJo02/gamelog/', 'https://www.pro-football-reference.com/players/J/JackLa00/gamelog/', 'https://www.pro-football-reference.com/players/C/CarrDe02/gamelog/']

Iterating through list of list in Python

This traverse generator function can be used to iterate over all the values:

def traverse(o, tree_types=(list, tuple)):
if isinstance(o, tree_types):
for value in o:
for subvalue in traverse(value, tree_types):
yield subvalue
else:
yield o

data = [(1,1,(1,1,(1,"1"))),(1,1,1),(1,),1,(1,(1,("1",)))]
print list(traverse(data))
# prints [1, 1, 1, 1, 1, '1', 1, 1, 1, 1, 1, 1, 1, '1']

for value in traverse(data):
print repr(value)
# prints
# 1
# 1
# 1
# 1
# 1
# '1'
# 1
# 1
# 1
# 1
# 1
# 1
# 1
# '1'


Related Topics



Leave a reply



Submit