Ely Fialkoff
Ely Fialkoff

Reputation: 652

Using multiple variables in a for loop in Python

I am trying to get a deeper understanding to how for loops for different data types in Python. The simplest way of using a for loop an iterating over an array is as

for i in range(len(array)):
    do_something(array[i])

I also know that I can

for i in array:
    do_something(i)

What I would like to know is what this does

for i, j in range(len(array)):
    # What is i and j here?

or

for i, j in array:
    # What is i and j in this case?

And what happens if I try using this same idea with dictionaries or tuples?

Upvotes: 29

Views: 196020

Answers (6)

Viknesh S K
Viknesh S K

Reputation: 121

Understood your question, explaining it using a different example.

1. Multiple Assignments using -> Dictionary

dict1 = {1: "Bitcoin", 2: "Ethereum"}

for key, value in dict1.items():
    print(f"Key {key} has value {value}")

print(dict1.items())

Output:

Key 1 has value Bitcoin
Key 2 has value Ethereum
dict_items([(1, 'Bitcoin'), (2, 'Ethereum')])

Explaining dict1.items():

dict1_items() creates values dict_items([(1, 'Bitcoin'), (2, 'Ethereum')])

It comes in pairs (key, value) for each iteration.

2. Multiple Assignments using -> enumerate() Function

coins = ["Bitcoin", "Ethereum", "Cardano"]
prices = [48000, 2585, 2]
for i, coin in enumerate(coins):
    price = prices[i]
    print(f"${price} for 1 {coin}")

Output:

$48000 for 1 Bitcoin
$2585 for 1 Ethereum
$2 for 1 Cardano

Explaining enumerate(coins):

enumerate(coins) creates values ((0, 'Bitcoin'), (1, 'Ethereum'), (2, 'Cardano'))

It comes in pairs (index, value) for each (one) iteration

3. Multiple Assignments using -> zip() Function

coins = ["Bitcoin", "Ethereum", "Cardano"]
prices = [48000, 2585, 2]
for coin, price in zip(coins, prices):
    print(f"${price} for 1 {coin}")

Output:

$48000 for 1 Bitcoin
$2585 for 1 Ethereum
$2 for 1 Cardano

Explaining

zip(coins, prices) create values (('Bitcoin', 48000), ('Ethereum', 2585), ('Cardano', 2))

It comes in pairs (value-list1, value-list2) for each (one) iteration.

Upvotes: 3

Tiago Peres
Tiago Peres

Reputation: 15451

Python's for loop is an iterator-based loop (that's why bruno desthuilliers says that it "works for all iterables (lists, tuples, sets, dicts, iterators, generators etc)". A string is also another common type of iterable).

Let's say you have a list of tuples. Using that nomenclature you shared, one can iterate through both the keys and values simultaneously. For instance:

tuple_list = [(1, "Countries, Cities and Villages"),(2,"Animals"),(3, "Objects")]

for k, v in tuple_list:
    print(k, v)

will give you the output:

1 Countries, Cities and Villages
2 Animals
3 Objects

If you use a dictionary, you'll also gonna be able to do this. The difference here is the need for .items()

dictionary = {1: "Countries, Cities and Villages", 2: "Animals", 3: "Objects"}

for k, v in dictionary.items():
    print(k, v)

The difference between dictionary and dictionary.items() is the following

dictionary: {1: 'Countries, Cities and Villages', 2: 'Animals', 3: 'Objects'}
dictionary.items(): dict_items([(1, 'Countries, Cities and Villages'), (2, 'Animals'), (3, 'Objects')])

Using dictionary.items() we'll get a view object containig the key-value pairs of the dictionary, as tuples in a list. In other words, with dictionary.items() you'll also get a list of tuples. If you don't use it, you'll get

TypeError: cannot unpack non-iterable int object

If you want to get the same output using a simple list, you'll have to use something like enumerate()

list = ["Countries, Cities and Villages","Animals", "Objects"]

for k, v in enumerate(list, 1): # 1 means that I want to start from 1 instead of 0
    print(k, v)

If you don't, you'll get

ValueError: too many values to unpack (expected 2)

So, this naturally raises the question... do I need always a list of tuples? No. Using enumerate() we'll get an enumerate object.

Upvotes: 6

bigcodeszzer
bigcodeszzer

Reputation: 940

I just wanted to add that, even in Python, you can get a for in effect using a classic C style loop by just using a local variable

l = len(mylist) #I often need to use this more than once anyways

for n in range(l-1):
    i = mylist[n]
    
    print("iterator:",n, " item:",i)

Upvotes: 0

wim
wim

Reputation: 362756

The simplest and best way is the second one, not the first one!

for i in array:
    do_something(i)

Never do this, it's needlessly complicating the code:

for i in range(len(array)):
    do_something(array[i])

If you need the index in the array for some reason (usually you don't), then do this instead:

for i, element in enumerate(array):
    print("working with index", i)
    do_something(element)

This is just an error, you will get TypeError: 'int' object is not iterable when trying to unpack one integer into two names:

for i, j in range(len(array)):
    # What is i and j here?

This one might work, assumes the array is "two-dimensional":

for i, j in array:
    # What is i and j in this case?

An example of a two-dimensional array would be a list of pairs:

>>> for i, j in [(0, 1), ('a', 'b')]:
...     print('i:', i, 'j:', j)
...     
i: 0 j: 1
i: a j: b

Note: ['these', 'structures'] are called lists in Python, not arrays.

Upvotes: 35

modesitt
modesitt

Reputation: 7210

Your third loop will not work as it will throw a TypeError for an int not being iterable. This is because you are trying to "unpack" the int that is the array's index into i, and j which is not possible. An example of unpacking is like so:

tup = (1,2)
a,b = tup

where you assign a to be the first value in the tuple and b to be the second. This is also useful when you may have a function return a tuple of values and you want to unpack them immediately when calling the function. Like,

train_X, train_Y, validate_X, validate_Y = make_data(data)

More common loop cases that I believe you are referring to is how to iterate over an arrays items and it's index.

for i, e in enumerate(array):
    ...

and

for k,v in d.items():  
    ...

when iterating over the items in a dictionary. Furthermore, if you have two lists, l1 and l2 you can iterate over both of the contents like so

for e1, e2 in zip(l1,l2):
    ...

Note that this will truncate the longer list in the case of unequal lengths while iterating. Or say that you have a lists of lists where the outer lists are of length m and the inner of length n and you would rather iterate over the elements in the inner lits grouped together by index. This is effectively iterating over the transpose of the matrix, you can use zip to perform this operation as well.

for inner_joined in zip(*matrix):  # will run m times
    # len(inner_joined) == m
    ...

Upvotes: 8

bruno desthuilliers
bruno desthuilliers

Reputation: 77912

Actually, "the simplest way of using a for loop an iterating over an array" (the Python type is named "list" BTW) is the second one, ie

for item in somelist:
    do_something_with(item)

which FWIW works for all iterables (lists, tuples, sets, dicts, iterators, generators etc).

The range-based C-style version is considered highly unpythonic, and will only work with lists or list-like iterables.

What I would like to know is what this does

for i, j in range(len(array)):
    # What is i and j here?

Well, you could just test it by yourself... But the result is obvious: it will raise a TypeError because unpacking only works on iterables and ints are not iterable.

or

for i, j in array:
    # What is i and j in this case?

Depends on what is array and what it yields when iterating over it. If it's a list of 2-tuples or an iterator yielding 2-tuples, i and j will be the elements of the current iteration item, ie:

array = [(letter, ord(letter)) for letter in "abcdef"]
for letter, letter_ord in array:
    print("{} : {}".format(letter, letter_ord))

Else, it will most probably raise a TypeError too.

Note that if you want to have both the item and index, the solution is the builtin enumerate(sequence), which yields an (index, item) tuple for each item:

array = list("abcdef")
for index, letter in enumerate(array):
    print("{} : {}".format(index, letter)

Upvotes: 2

Related Questions