user9990443
user9990443

Reputation:

csv dictionary does not reset to the beginning when looping through it multiple times

I am looping a CSV file, which is opened as dictionary. The problem is that while I loop through the rows in the dictionary, the main for loop goes to the next item. The dictionary does not reset to the first item when running the for loop. So if it gets to the last row, it doesn't change.

names = ['a', 'b', 'c', 'd', 'e', 'f']
source1_csv = open("output.csv", mode='r')
dictionary_csv = csv.DictReader(source1_csv)

for letters in names:
    for entry in dictionary_csv:
        print(entry["name"])
        if entry['name'] == letters:
            print("found it")

You can use any CSV file, just replace the key in the entry, and notice that if there is no match on the outer for loop, once that the next item in the names is selected, the inner for loop for the dictionary will just exit because the dictionary is already on the last position and does not reset.

How do I avoid this, so the position of the dictionary is reset and parse through every row for every entry of the names list?

Upvotes: 2

Views: 771

Answers (2)

Ahmad Khan
Ahmad Khan

Reputation: 2703

Solution 1:

From your code above, it doesn't look like that you need to iterate over the entire csv multiple times, you can just switch the loops like:

for entry in dictionary_csv:
    for letters in names:
        print(entry["name"])
        if entry['name'] == letters:
            print("found it")

Switching the loop over dictionary_csv to outer loop will avoid looping over csv multiple times.

Solution 2:

But if you don't want to change the order of loops, you can simply convert the DictReader to list before consuming it yourself. This way, list will consume the reader, and return you a list of it, and you can iterate over it multiple times:

dictionary_csv = list(csv.DictReader(source1_csv))

But if your csv is rather big, creating a list out of it isn't recommended, as list size will be big.

Solution 3:

Instead of creating a list, you can also seek the source file source1_csv to 0 before the inner loop:

for letters in names:
    source1_csv.seek(0)
    for entry in dictionary_csv:
        print(entry["name"])
        if entry['name'] == letters:
            print("found it")

It will take the source file to the start, and dictionary_csv will read it again for you.

Edit:

As @merlyn pointed out in below comments, that the solution 3 will not work entirely correctly, because after seeking to 0, dictionary_csv will interpret the first line of the csv (headers) as a separate data row. So, you'll have to ignore a line after seeking to 0.

source1_csv.seek(0)
source1_csv.readline()

Or, re-instantiate dictionary_csv everytime you seek source1_csv (For that, you can see @merlyn's answer below).

Upvotes: 1

merlyn
merlyn

Reputation: 2361

csv doesn't provide a way to reset the iterator but the file object interface does. You can reset a file to it's starting position using file.seek(0).

names = ['a', 'b', 'c', 'd', 'e', 'f']
source1_csv = open("output.csv", mode='r')

for letters in names:
    source1_csv.seek(0)
    for entry in csv.DictReader(source1_csv):
        print(entry["name"])
        if entry['name'] == letters:
            print("found it")

Of course, you can also store the entries in a list and iterate on the as many time as you want. But that won't with files too large to store in memory.

Upvotes: 1

Related Questions