Python equivalent for C ++ begin () and end () for custom classes

Say you have a dictionary whose keys are integer. Values ​​are also dictionaries whose keys are strings and whose values ​​are numpy arrays. Sort of:

custom = {1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2:{'c': np.zeros(20), 'd': np.zeros(200)}} 

I used this special data structure quite a bit in the code, and every time I need to iterate over each of the lines in the numpy arrays of this structure, I have to do:

 for d, delem in custom.items(): for k, v in delem.items(): for row in v: print(row) 

Is it possible to encapsulate this behavior in Γ  la C ++ functions, where you can really implement custom begin() and end() ? In addition, the iterator should also have key information in the corresponding dictionaries. I imagine something like:

 for it in custom: d, e, row = *it # then do something with these 
+3
source share
4 answers
 import numpy as np custom = { 1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2:{'c': np.zeros(20), 'd': np.zeros(200)} } my_gen = ( (key, subkey, np_array) for (key, a_dict) in custom.items() for subkey, np_array in a_dict.items() ) for key, subkey, np_array in my_gen: print(key, subkey, np_array) --output:-- 1 b [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 1 a [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 2 d [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 2 c [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] 

Or you could restore your data structure to something more useful for your purposes:

 import numpy as np custom = { 1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2:{'c': np.zeros(20), 'd': np.zeros(200)} } #Create a *list* of tuples: converted_data = [ (np_array, subkey, key) for (key, a_dict) in custom.items() for subkey, np_array in a_dict.items() ] for np_array, subkey, key in converted_data: print(key, subkey, np_array) 

Creating a custom iterator:

 class Dog: def __init__(self, data): self.data = data self.max = len(data) self.index_pointer = 0 def __next__(self): index = self.index_pointer if index < self.max: current_val = self.data[index] self.index_pointer += 1 return current_val else: raise StopIteration class MyIter: def __iter__(self): return Dog([1, 2, 3]) for i in MyIter(): print(i) --output:-- 1 2 3 

__iter__() just needs to return an object that implements the __next__() method, so you can combine these two classes as follows:

 class MyIter: def __init__(self, data): self.data = data self.max = len(data) self.index_pointer = 0 def __iter__(self): return self #I have a __next__() method, so let return me! def __next__(self): index = self.index_pointer if index < self.max: current_val = self.data[index] self.index_pointer += 1 return current_val else: raise StopIteration for i in MyIter([1, 2, 3]): print(i) --output:-- 1 2 3 

More complex __next__() method:

 import numpy as np class CustomIter: def __init__(self, data): self.data = data self.count = 0 def __iter__(self): return self def __next__(self): count = self.count self.count += 1 if count == 0: #On first iteration, retun a sum of the keys return sum(self.data.keys()) elif count == 1: #On second iteration, return the subkeys in tuples subkeys = [ a_dict.keys() for a_dict in self.data.values() ] return subkeys elif count == 2: #On third iteration, return the count of np arrays np_arrays = [ np_array for a_dict in self.data.values() for np_array in a_dict.values() ] return len(np_arrays) else: #Quit after three iterations raise StopIteration custom = { 1: {'a': np.zeros(10), 'b': np.zeros(100)}, 2:{'c': np.zeros(20), 'd': np.zeros(200)} } for i in CustomIter(custom): print(i) --output:-- 3 [dict_keys(['b', 'a']), dict_keys(['d', 'c'])] 4 
+1
source

There are several ways to do this. yield may be the easiest, as it is a hard climb to create an interning class for you.

 def custom_dict_iter(custom): for d, delem in custom.items(): for k, v in delem.items(): for row in v: yield d, k, row for d, k, row in custom_dict_iter(my_custom_dict): print(d, k, row) 
+4
source

Take a look - this is more like Java Iterable or C # IEnumerable than the beginning / end of C ++. You can define it more easily by defining the __iter__ method as generator .

The only thing you need to do so that your custom its own class with these methods, and not a simple dictionary, but I assume this is also true in C ++.

+2
source

As a more pythonic way, you can use a nested list comprehension that runs at C language speed inside the interpreter:

 >>> [[(i,key,t) for t in value] for i,j in custom.items() for key,value in j.items()] 

And if you want to get an iterator, you can use a generator expression instead of understanding the list.

 >>> ([(i,key,t) for t in value] for i,j in custom.items() for key,value in j.items()) 
0
source

All Articles