Skip to content Skip to sidebar Skip to footer

Python Equivalent Of C++ Begin() And End() For Custom Classes

Say you have a dictionary whose keys are integers. The values are also dictionaries whose keys are strings and whose values are numpy arrays. Something like: custom = {1: {'a': np.

Solution 1:

There are multiple ways to do this. yield may be the simplest as it does the heavy lifting of building an interator class for you.

def custom_dict_iter(custom):
    ford, delem in custom.items():
        fork, v in delem.items():
            forrowin v:
                yield d, k, row

ford, k, row incustom_dict_iter(my_custom_dict):
    print(d, k, row)

Solution 2:

Look up the iterator protocol - this is more similar to Java's Iterable or C#'s IEnumerable than C++'s begin/end. You can define it more easily by defining the __iter__ method as a generator.

The only thing is, you'd need to make your custom have its own class with these methods rather than a plain dictionary, but I assume that's also true in C++.

Solution 3:

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 reconstitute your data structure into something that is 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:

classDog:
    def__init__(self, data):
        self.data = data
        self.max = len(data)
        self.index_pointer = 0def__next__(self):
        index = self.index_pointer

        if index < self.max:
            current_val = self.data[index]
            self.index_pointer += 1return current_val
        else:
            raise StopIteration


classMyIter:
    def__iter__(self):
        return Dog([1, 2, 3])


for i in MyIter():
    print(i)

--output:--
123

__iter__() just needs to return an object that implements a __next__() method, so you can combine those two classes like this:

classMyIter:
    def__init__(self, data):
        self.data = data
        self.max = len(data)
        self.index_pointer = 0def__iter__(self):
        return self  #I have a __next__() method, so let's return me!def__next__(self):
        index = self.index_pointer

        if index < self.max:
            current_val = self.data[index]
            self.index_pointer += 1return current_val
        else:
            raise StopIteration

for i in MyIter([1, 2, 3]):
    print(i)

--output:--
123

A more complex __next__() method:

import numpy as np

classCustomIter:
    def__init__(self, data):
        self.data = data
        self.count = 0def__iter__(self):
        return self

    def__next__(self):
        count = self.count
        self.count += 1if count == 0:  #On first iteration, retun a sum of the keysreturnsum(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()
            ]

            returnlen(np_arrays)

        else:  #Quit after three iterationsraise 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

Solution 4:

As a more pythonic way you can use a nested list comprehension which performs at C language speed inside the interpreter:

>>> [[(i,key,t) fortin value] fori,j in custom.items() forkey,value in j.items()]

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

>>> ([(i,key,t) fortin value] fori,j in custom.items() forkey,value in j.items())

Post a Comment for "Python Equivalent Of C++ Begin() And End() For Custom Classes"