Skip to content

Instantly share code, notes, and snippets.

@kcsaff
Created January 14, 2015 00:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kcsaff/50b918b1c12c95c8500e to your computer and use it in GitHub Desktop.
Save kcsaff/50b918b1c12c95c8500e to your computer and use it in GitHub Desktop.
Simple Python Vector class
import operator
class Vector(object):
def __init__(self, data, typ=None, copy=True):
self._type = typ
if isinstance(data, int):
self.data = [self._type() for _ in range(data)]
elif copy:
self.data = list(data) # copy the data
else: # This is (probably) a slice or copy is unnecessary for some other reason
self.data = data
if self._type is None:
self._type = type(self.data[0])
def apply(self, fun):
"""
Equivalent to `Vector(fun(x) for x in self)`
>>> Vector([{1,2,3}, {4,5}]).apply(len)
Vector([3, 2])
"""
return Vector(fun(x) for x in self)
def __iter__(self):
return iter(self.data)
def __getitem__(self, key):
if isinstance(key, slice):
return self.__class__(self.data[key], self._type, copy=False)
else:
return self.data[key]
def __len__(self):
"""
Return length of data.
>>> len(Vector([{1,2,3}, {5}, {}, {}]))
4
"""
return len(self.data)
def shift(self, amount):
"""
Shift all users left (for positive amount) or right (for negative amount), while leaving the length unchanged.
Key to remembering is that v.shift(a)[b] == v[a+b] for b, a+b positive
>>> Vector([{1,2}, {3}, {4, 5}]).shift(-1)
Vector([set(), {1, 2}, {3}])
>>> Vector([{1,2}, {3}, {4, 5}]).shift(+1)
Vector([{3}, {4, 5}, set()])
"""
if amount < 0:
data = [self._type() for _ in range(abs(amount))] + self.data[:amount]
else:
data = self.data[amount:] + [self._type() for _ in range(abs(amount))]
return self.__class__(data, self._type, copy=False)
def __repr__(self):
"""
Return `repr` of this object.
>>> repr(Vector([{1,2}, {3}, {4, 5}]))
'Vector([{1, 2}, {3}, {4, 5}])'
"""
return '{cls}({data})'.format(cls=self.__class__.__name__, data=self.data)
# Operators used for the calculator function
def __pos__(self):
return self.apply(operator.pos)
def __neg__(self):
return self.apply(operator.neg)
def __and__(self, other):
"""
Return intersection of my items with other's items.
>>> Vector([{1,2,3}, {4,5}, {1,2}]) & Vector([{2,5}, {1,4}, {7,8}])
Vector([{2}, {4}, set()])
"""
return self._apply_function2(other, operator.and_)
def __or__(self, other):
"""Return union of my users with other users."""
return self._apply_function2(other, operator.or_)
def __xor__(self, other):
"""Return exclusive or of my users with other users."""
return self._apply_function2(other, operator.xor)
def __add__(self, other):
"""Add one vector to another."""
return self._apply_function2(other, operator.add)
def __sub__(self, other):
"""Subtract one vector from another."""
return self._apply_function2(other, operator.sub)
def __mul__(self, other):
"""Multiply one vector by another.
>>> Vector([1,2,3]) * Vector([2,2,0])
Vector([2, 4, 0])
>>> Vector([1,2,3]) * [2,2,0]
Vector([2, 4, 0])
>>> Vector([1,2,3]) * 2
Vector([2, 4, 6])
"""
return self._apply_function2(other, operator.mul)
def __truediv__(self, other):
"""Return vector of my sizes divided by other object."""
return self._apply_function2(other, (lambda x, y: operator.truediv(x,y) if y else None))
def _apply_function2(self, other, fun):
try:
otherlen = len(other)
except TypeError: # No length, must be scalar
return Vector(
fun(self.data[i], other)
if self.data[i] is not None
else None
for i in range(len(self))
)
else:
if len(self) != len(other):
raise Exception('Vector lengths not the same.')
return Vector(
fun(self.data[i], other[i])
if self.data[i] is not None and other[i] is not None
else None
for i in range(len(self))
)
def _return_same_thing(x):
return x
if __name__ == '__main__':
import doctest
doctest.testmod()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment