Python 用 lambda 修改元组
Python modify tuple with lambda
我有一个如下所示的元组:
(((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
因此元组中有4个元组,每个元组存储一个坐标(另一个元组)和一个布尔值。
(我不使用 dict 或 list 因为我需要它是可哈希的)
有没有一种聪明的方法可以将给定坐标的 bool 更改为 true?
所以我想在一行中表达的是:
在状态下将 pair[1] 设置为 True,其中 pair[0] = (givenX, givenY)
在 python 中有没有聪明的方法来做到这一点?
更新:
谢谢大家的回答。这是我最后所做的:
state = dict(state)
if (givenX, givenY) in state.keys():
state[(givenX, givenY)] = True
state = tuple(state.items())
由于 bool
是不可变的(毕竟它们是普通整数),您必须重建元组才能修改它们:
tuple(x if x[0] != (givenX, givenY) else (x[0], True) for x in your_tuple)
虽然我认为最简单的方法是使用dict
并在进行必要的修改后将其转换为tuple
:
In [23]: d = {(1, 2): False}
In [24]: d[1, 2] = True
In [25]: tuple(d.items())
Out[25]: (((1, 2), True),)
显然,您不能就地修改元组,但可以使用生成器表达式创建一个新元组:
given = (givenX, givenY)
result = tuple((p, p==given) for p, _ in original_tuple)
如果您已经将某些值设置为 True
并希望保持这样:
result = tuple((p1, p2 or p1==given) for p1, p2 in original_tuple)
是的,您可以使用 lambda 函数执行此操作。
right = 5 # dummy value
top = 7 # dummy value
search = (1,7) # needle coordinates
tups = (((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
print map(lambda x: (x[0], not x[1]) if x[0]==search else (x[0], x[1]), tups)
# [((1, 1), False), ((1, 7), True), ((5, 1), False), ((5, 7), False)]
但是这会生成元组列表,因此您需要再次将其转换为元组
print tuple(map(lambda x: (x[0], not x[1]) if x[0]==search else (x[0], x[1]), tups))
# (((1, 1), False), ((1, 7), True), ((5, 1), False), ((5, 7), False))
听起来您已经到了将数据封装在一组 类 中的好主意。
您可以使用 collections.namedtuple
作为 类 的基础,这将创建不可变对象,可以轻松地为其创建具有一个或多个不同值的新实例。您甚至可以将您创建的命名元组子类化并添加您自己的方法,这将有助于轻松替换对象中的值,同时保持代码简洁和可读,例如。
from collections import namedtuple
right = "right"
top = "top"
tuple_data = (((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
# create a subclass of tuple whose name is the first argument, and the second argument
# is space separated fields which are aliases for accessing the class as a tuple.
# eg. Point(1, 2).x == Point(1, 2)[0]
Point = namedtuple("Point", "x y")
_PointValueBase = namedtuple("PointValue", "point value")
_RectangleBase = namedtuple("Rectangle", "leftbottom lefttop rightbottom righttop")
class PointValue(_PointValueBase):
def replace_if_point_equal(self, point, value):
if self.point == point:
return self._replace(value=value)
return self
class Rectangle(_RectangleBase):
def replace(self, point, value):
return Rectangle._make(pv.replace_if_point_equal(point, value) for pv in self)
# convert tuple_data to a Rectangle
rect = Rectangle(*(PointValue(Point(*p), v) for p, v in tuple_data))
print(rect) # nice textual representation
assert eval(str(rect)) == rect # which is also machine readable
assert isinstance(rect, tuple) # is a subclass of tuple
assert hash(tuple_data) == hash(rect) # so its hash is the same
given_point = Point(x=right, y=top)
new_rect = rect.replace(given_point, value=True)
print(new_rect)
assert new_rect.righttop.value is True
我有一个如下所示的元组:
(((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
因此元组中有4个元组,每个元组存储一个坐标(另一个元组)和一个布尔值。
(我不使用 dict 或 list 因为我需要它是可哈希的)
有没有一种聪明的方法可以将给定坐标的 bool 更改为 true?
所以我想在一行中表达的是:
在状态下将 pair[1] 设置为 True,其中 pair[0] = (givenX, givenY)
在 python 中有没有聪明的方法来做到这一点?
更新:
谢谢大家的回答。这是我最后所做的:
state = dict(state)
if (givenX, givenY) in state.keys():
state[(givenX, givenY)] = True
state = tuple(state.items())
由于 bool
是不可变的(毕竟它们是普通整数),您必须重建元组才能修改它们:
tuple(x if x[0] != (givenX, givenY) else (x[0], True) for x in your_tuple)
虽然我认为最简单的方法是使用dict
并在进行必要的修改后将其转换为tuple
:
In [23]: d = {(1, 2): False}
In [24]: d[1, 2] = True
In [25]: tuple(d.items())
Out[25]: (((1, 2), True),)
显然,您不能就地修改元组,但可以使用生成器表达式创建一个新元组:
given = (givenX, givenY)
result = tuple((p, p==given) for p, _ in original_tuple)
如果您已经将某些值设置为 True
并希望保持这样:
result = tuple((p1, p2 or p1==given) for p1, p2 in original_tuple)
是的,您可以使用 lambda 函数执行此操作。
right = 5 # dummy value
top = 7 # dummy value
search = (1,7) # needle coordinates
tups = (((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
print map(lambda x: (x[0], not x[1]) if x[0]==search else (x[0], x[1]), tups)
# [((1, 1), False), ((1, 7), True), ((5, 1), False), ((5, 7), False)]
但是这会生成元组列表,因此您需要再次将其转换为元组
print tuple(map(lambda x: (x[0], not x[1]) if x[0]==search else (x[0], x[1]), tups))
# (((1, 1), False), ((1, 7), True), ((5, 1), False), ((5, 7), False))
听起来您已经到了将数据封装在一组 类 中的好主意。
您可以使用 collections.namedtuple
作为 类 的基础,这将创建不可变对象,可以轻松地为其创建具有一个或多个不同值的新实例。您甚至可以将您创建的命名元组子类化并添加您自己的方法,这将有助于轻松替换对象中的值,同时保持代码简洁和可读,例如。
from collections import namedtuple
right = "right"
top = "top"
tuple_data = (((1, 1), False), ((1, top), False), ((right, 1), False), ((right, top), False))
# create a subclass of tuple whose name is the first argument, and the second argument
# is space separated fields which are aliases for accessing the class as a tuple.
# eg. Point(1, 2).x == Point(1, 2)[0]
Point = namedtuple("Point", "x y")
_PointValueBase = namedtuple("PointValue", "point value")
_RectangleBase = namedtuple("Rectangle", "leftbottom lefttop rightbottom righttop")
class PointValue(_PointValueBase):
def replace_if_point_equal(self, point, value):
if self.point == point:
return self._replace(value=value)
return self
class Rectangle(_RectangleBase):
def replace(self, point, value):
return Rectangle._make(pv.replace_if_point_equal(point, value) for pv in self)
# convert tuple_data to a Rectangle
rect = Rectangle(*(PointValue(Point(*p), v) for p, v in tuple_data))
print(rect) # nice textual representation
assert eval(str(rect)) == rect # which is also machine readable
assert isinstance(rect, tuple) # is a subclass of tuple
assert hash(tuple_data) == hash(rect) # so its hash is the same
given_point = Point(x=right, y=top)
new_rect = rect.replace(given_point, value=True)
print(new_rect)
assert new_rect.righttop.value is True