Is it possible to call an iterator in a defaultdict to get the next key-value?

Viewed 154

Python 3.6.x

I've got a defaultdict, which is named xref_to_records. It has got strings as keys, and lists as values.

for k, v in xref_to_records.items():
    print(type(k))
    print(type(xref_to_records[k]))
    break

It produces:

<class 'str'>
<class 'list'>

What I'm trying to do is to iterate through its items to compare the values list of a key against the next one. I know this question was probably already answered somewhere, but I couldn't figure to make work any of the provided approaches.

I've tried to iterate through the lenght of keys, but it doesn't work.

keys = xref_to_records.keys()
    for i in range(len(keys)):
    this_key = keys[i]

It raises me a TypeError:

TypeError: 'dict_keys' object does not support indexing

I've tried also to iterate through keys using next() but unsuccessfully.

frick = None
for k,v in iter(xref_to_records.items()):
    if k != frick:
        res = next(k, None)
        print(res)
    break

Again a TypeError :

TypeError: 'str' object is not an iterator

Expected output

for k, v in xref_to_records.items():
     somefunctions(k)
     somefunctions(next(k))
2 Answers

Strictly speaking, a dictionary does not have a specific order. However, in never versions of Python, the items in a dict should be iterated in the original order of insertion, and since defaultdict is a subclass of dict, the same should hold there, too.

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for i in range(4): d[i] = list(range(i+1))
>>> d[10] = []
>>> d[4] = []
>>> d
defaultdict(list, {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 1, 2, 3], 4: [], 10: []})
>>> list(d)
[0, 1, 2, 3, 10, 4]

You can then get two iter of the dictionary, advance one of those once using next, and zip them to get pairs of (current, next) elements. (Here, it's just pairs of the keys, but of course you can just get the corresponding values from the dictionary.)

>>> from itertools import tee
>>> it1, it2 = tee(iter(d))
>>> next(it2)
>>> for a, b in zip(it1, it2):
...     print(a, b)
...
0 1
1 2
2 3
3 10
10 4

For older versions of Python, you might have to use a collections.OrderedDict instead. If, instead, you do not want insertion order but e.g. lexicographic ordering, you can just get the iter from the sorted keys.

see below

from collections import defaultdict
xref_to_records = defaultdict(list)

xref_to_records['A'].append(9)
xref_to_records['A'].append(12)
xref_to_records['B'].append(99)
xref_to_records['B'].append(112)
xref_to_records['C'].append(99.34)
xref_to_records['C'].append(112.88)
xref_to_records['C'].append(4112.88)

keys = list(xref_to_records.keys())
for idx,key in enumerate(keys):
    if idx > 0:
        print('compare:')
        print('current:' + str(xref_to_records[key]))
        print('previous: ' + str(xref_to_records[keys[idx-1]]))
        print('')
    

output

compare:
current:[99, 112]
previous: [9, 12]

compare:
current:[99.34, 112.88, 4112.88]
previous: [99, 112]
Related