我需要在Python中表示不可变向量("向量"在线性代数中,而不是在编程中).元组似乎是一个明显的选择.
麻烦的是我需要实现添加和标量乘法之类的东西.如果a和b是矢量,并且c是一个数字,我能想到的最好的是:
tuple(map(lambda x,y: x + y, a, b)) # add vectors 'a' and 'b'
tuple(map(lambda x: x * c, a)) # multiply vector 'a' by scalar 'c'
Run Code Online (Sandbox Code Playgroud)
这似乎不优雅; 应该有一个更清晰,更简单的方法来完成这个 - 更不用说避免调用tuple,因为map返回一个列表.
有更好的选择吗?
Ale*_*lli 10
不可变类型在Python及其第三方扩展中非常罕见; OP正确地声称"线性代数有足够的用途,似乎我不可能自己动手" - 但我知道线性代数的所有现有类型都是可变的!因此,随着OP是不变性坚信,有是什么好说的了,但卷制自己的路线.
并非所有涉及的内容都很多,例如,如果您特别需要2-d向量:
import math
class ImmutableVector(object):
__slots__ = ('_d',)
def __init__(self, x, y):
object.__setattr__(self, _d, (x, y))
def __setattr__(self, n, v):
raise ValueError("Can't alter instance of %s" % type(self))
@property
def x(self):
return self._d[0]
@property
def y(self):
return self._d[1]
def __eq__(self, other):
return self._d == other._d
def __ne__(self, other):
return self._d != other._d
def __hash__(self):
return hash(self._d)
def __add__(self, other):
return type(self)(self.x+other.x, self.y+other.y)
def __mul__(self, scalar):
return type(self)(self.x*scalar, self.y*scalar)
def __repr__(self):
return '%s(%s, %s)' % (type(self).__name__, self.x, self.y)
def __abs__(self):
return math.hypot(self.x, self.y)
Run Code Online (Sandbox Code Playgroud)
我"免费投入"了一些额外内容,例如.x和.yR/O属性,漂亮的字符串表示,集合中的可用性或作为键的键(为什么还有人想要不变性? - ),低内存占用,abs(v)给出v向量-length - 我确信你可以想到其他"不会很酷的方法"的方法和操作符,这取决于你的应用领域,而且它们也会一样容易.如果你需要其他的维度,它不会更难,虽然一点点,因为少可读.x,.y符号不施加任何更多;-)(但我会用genexps,没有map).
小智 8
通过继承元组,你可以很容易地创建一个漂亮的Vector类.这里有足够的代码来提供向量的添加,以及通过标量乘以向量.它为您提供任意长度向量,并且可以处理复数,整数或浮点数.
class Vector(tuple):
def __add__(self, a):
# TODO: check lengths are compatable.
return Vector(x + y for x, y in zip(self, a))
def __mul__(self, c):
return Vector(x * c for x in self)
def __rmul__(self, c):
return Vector(c * x for x in self)
a = Vector((1, 2, 3))
b = Vector((2, 3, 4))
print a + b
print 3 * a
print a * 3
Run Code Online (Sandbox Code Playgroud)
小智 6
尽管使用像NumPy这样的库似乎是OP的解决方案,但我认为在一个简单的解决方案中仍然有一些价值,它不需要额外的库,并且可以使用iterables保持不可变.
使用itertools和operators模块:
imap(add, a, b) # returns iterable to sum of a and b vectors
Run Code Online (Sandbox Code Playgroud)
这种实现很简单.它不使用lambda也不使用任何list-tuple转换,因为它是基于迭代器的.
from itertools import imap
from operator import add
vec1 = (1, 2, 3)
vec2 = (10, 20, 30)
result = imap(add, vec1, vec2)
print(tuple(result))
Run Code Online (Sandbox Code Playgroud)
产量:
(11, 22, 33)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10828 次 |
| 最近记录: |