简体   繁体   中英

How to use __add__ method to add sparse vectors in python

I am given an assignment to add two sparse vectors using special methods in SparseVec(length) class.I have limited understanding of special methods and method overloading, can you please describe what i am missing in the following code and what exactly is method overloading? I have two alternatives: using stand alone functions and class methods(OOP). I want to know the advantage of the later (OOP).

Stand-alone function (Works fine)

def SparseVec(numbers):
    dic={}
    for key,val in enumerate(numbers):
        if val:
            dic[key]=val
    return dic

numbers=[-1,0,9.2,0]
a=SparseVec(numbers)
print(a)

numbers2=[0,1,0,0,0]
b=SparseVec(numbers2)
print(b)

#Adds and merges values with keys in two dictionaries
def merged_dictionaries(a,b):
    merged_dict={}
    for key in a:
        if key in b:
            new_value=a[key]+b[key]
        else:
            new_value=a[key]
        merged_dict[key]=new_value
    for key in b:
        if key not in merged_dict:
            merged_dict[key]=b[key]
    return merged_dict
c=merged_dictionaries(a,b)
for key, val in c.items(): # SparseVec iterator
    print ('c[%d]=%g ' % (key,val))
print(c)

class method(OOP)-(Defective)

#Implements a Sparse vector (vector with many zero values) and adds two sparse vectors
class SparseVec:
    #initializes the instance with given length
    def __init__(self,length):
        self.length=length
        self.data={}
    def __str__(self):
        return 'Dense Vector {}'. format(self.data)
    #Returns the length of the vector
    def __len__(self):
        return len(self.data)
    # Returns nonzeros from the given(self) dictionary
    def __getitem__(self, item):
        return self.data
    def __setitem__(self, key, val):
        #To set a value by its key
        self.data[key]= val

    def nonzeros(self):
        nonzerodict = {}
        for key, val in enumerate(self):
            if val:
                nonzerodict[key] = val
        return nonzerodict
    def __add__(self, other):
        c = {}
        for key in self:
            if key in other:
                new_value = self[key]+ other[key]
            else:
                new_value = self[key]
            c[key] = new_value
        for key in other:
            if key not in c:
                c[key] = other[key]
        return c

a = SparseVec(4)
a[2] = 9.2
a[0] = -1
print(a)
print(a.nonzeros())
b = SparseVec(5)
b[1] = 1
print(b.nonzeros())
c=a+b
print(c)

You need to add the components of each vector pairwise, and return a SparseVector object:

class SparseVec:

    def __init__(self, dimension):
        self.dimension = dimension
        self.data = {}

    def __str__(self):
        return 'Sparse Vector {}'. format(self.data)

    def __len__(self):
        return self.dimension    # what matters is the size of the vector, not the length of the stored data

    def __getitem__(self, key):
        assert isinstance(key, int)
        assert 0 <= key < self.dimension, 'the key must be compatible with the vector dimension' 
        try:
            return self.data[key]
        except KeyError:
            return 0     # must return zero if valid key but no entry

    def __setitem__(self, key, val):
        assert isinstance(key, int)
        assert 0 <= key < self.dimension, 'this vector does not have an appropriate dimension'
        if val != 0:     # avoid cluttering with zero values
            self.data[key] = val

    def purge_zeros(self):  # <-- resparsifies a vector by purging the zero values
        nonzerodict = {}
        for key, val in self.data.items():
            if val != 0:
                nonzerodict[key] = val
        self.data = nonzerodict

    def __add__(self, other):
        assert self.dimension == other.dimension, 'vectors must have the same dimension'
        resulting_vector = SparseVec(self.dimension)
        c = {k:v for k, v in self.data.items()}  # <-- copies self data
        for k, v in other.data.items():
            try:
                c[k] += v
            except KeyError:
                c[k] = v
        resulting_vector.data = c
        resulting_vector.purge_zeros()
        return resulting_vector

tests:

a = SparseVec(4)
b = SparseVec(4)
a.data = {0: 2, 1: 1}
b.data = {0: -2, 1: 2, 2: 4}
print(a + b)
print(a[0], a[1], a[2], a[3])
print(b[0], b[1], b[2], b[3])
a[3] = -3
print(a[0], a[1], a[2], a[3])

output:

Sparse Vector {1: 3, 2: 4}
2 1 0 0
-2 2 4 0
2 1 0 -3

Overloading a class method is essentially writing a method that would usually be handled by a default method in Python and replacing it with your own method for that class.

This is the default add method from Python 3 docs: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

I'm not sure on why you are using a dict for this rather than a list without more context, but the following should work:

c = a.add(b)
print(c)

a is an instance of the SparseVec class, so in order to access the add method we call a.add() and pass in the other object we wish to add to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM