Pra*_*MiD 5 python lambda intersection
我想建立两个python集的交集,但是我需要有一个自定义的相等性来做到这一点。进行交点时,是否可以直接指定“相等”?例如由于lambda表达式?
我知道可以通过重写eq来解决,但是我必须在具有不同“ 等式 ”的同一个类上做几个交集。
谢谢!
前言
通过使用正确的术语,您尝试做的事情具有完美的数学意义。您所指的“等式”实际上是等价关系。基本上,等距关系描述了将集合的两个元素标识为“等效”必须满足的条件。
等价关系将集合分解为所谓的等价类。每个等价类都是一个子集,其中包含原始集合的所有元素,这些元素相对于等价关系成对等效。
平等本身是等价关系的特例。相等关系的每个等价类仅包含一个元素,因为集合中的每个元素仅等同于自身。
游览:当谈到面向对象的语言中的对象平等时,这是造成混乱的根源。在数学中,一个对象(即集合的成员)仅存在一次(它仅等于自身)。但是,在面向对象的编程中,存在身份和相等性的区别。可能存在具有不同身份(Python:a is b评估为false)的对象,这些对象相等(a == b评估为true),例如float 2.0和int 2。这意味着,Python的__eq__函数在所有Python对象的集合上实现了默认的等价关系,这称为“相等”。游览结束
关于任何等价类,更重要的一点是,它可以由单个任意成员(称为“代表”)表示。这意味着您只需要对照等效类的一位已知代表检查该关系,即可确定元素是否属于该等效类。这将在下面的代码中利用。
回答问题
对应于您的问题,我们有以下设置。我们有两个集合A,B它们实际上是更大集合的子集M。因为M存在许多不同的等价关系,并且对于每种关系,我们都需要以某种方式“相交” A和B“关于等价关系”。
唯一有意义的方法是用其等价类替换成员,A并B检查两个投影中确实发生了哪些等价类。
这比听起来容易:关于一个等价关系的相交配方:
A(和B)元素进行分组,使每个组由成对等效元素组成。(这些组类似于等效类)G的A,检查是否有一组H的B,使得元件G和H是等价的。如果是,G并且H属于相同的等价类,即该等价类是交集的成员。请注意,所需的输出实际上取决于您的用例。例如,您可以使用匹配Gs和Hs 的所有并集的列表(这是下面要强调的内容)。另外,如果您仅对交点中每个等价类的任意元素感兴趣,则可以选择G(或H)的第一个成员。(这__main__部分显示为[c[0] for c in intersection]。)
下面的代码示例使用列表(不是集合或代表)实现了如上所述的幼稚相交,该列表适用于任何对象和任何等价关系。该Intersector班采取与如果两个参数是等效的,则返回true两个参数的函数。
我认为您可以针对用例轻松进行优化,以保存循环和比较。
重要说明:当然,您需要验证您的“等式”是非对等关系(反射性,对称性,传递性,请参见上面的Wiki链接)。
码:
from __future__ import print_function
class Intersector(object):
def __init__(self, relation):
self.relation = relation
def intersect(self, a, b):
a_classes = self.get_equivalence_classes(a)
print('Groups of A:', a_classes)
b_classes = self.get_equivalence_classes(b)
print('Groups of B:', b_classes)
return self.intersect_classes(a_classes, b_classes)
def get_equivalence_classes(self, elements):
eq_classes = []
for element in elements:
match = False
for eq_class in eq_classes:
if self.relation(element, eq_class[0]):
eq_class.append(element)
match = True
break
if not match:
eq_classes.append([element])
return eq_classes
def intersect_classes(self, a, b):
def search_in_B(g):
for h in b:
if self.relation(g[0], h[0]):
return h
result = []
for g in a:
h = search_in_B(g)
if h is not None:
result.append(g+h)
print('Intersection:', result)
return result
if __name__ == '__main__':
A = set([4, 2, 1, 7, 0])
B = set([1, 13, 23, 12, 62, 101, 991, 1011, 1337, 66, 666])
print('A:', A)
print('B:', B)
print(79*'-')
print('Intersection with respect to the relation:')
print('a and b have the same remainder divided by 5')
intersection = Intersector(lambda x, y : x % 5 == y % 5).intersect(A, B)
reduced = [c[0] for c in intersection]
print('Intersection reduced to representatives:', reduced)
print(79*'-')
print('Intersection with respect to the relation:')
print('a and b have the same remainder divided by 7')
intersection = Intersector(lambda x, y : x % 7 == y % 7).intersect(A, B)
reduced = [c[0] for c in intersection]
print('Intersection reduced to representatives:', reduced)
Run Code Online (Sandbox Code Playgroud)
输出:
A: set([0, 1, 2, 4, 7])
B: set([1, 66, 101, 12, 13, 1011, 23, 1337, 666, 62, 991])
-------------------------------------------------------------------------------
Intersection with respect to the relation:
a and b have the same remainder divided by 5
Groups of A: [[0], [1], [2, 7], [4]]
Groups of B: [[1, 66, 101, 1011, 666, 991], [12, 1337, 62], [13, 23]]
Intersection: [[1, 1, 66, 101, 1011, 666, 991], [2, 7, 12, 1337, 62]]
Intersection reduced to representatives: [1, 2]
-------------------------------------------------------------------------------
Intersection with respect to the relation:
a and b have the same remainder divided by 7
Groups of A: [[0, 7], [1], [2], [4]]
Groups of B: [[1, 666], [66, 101, 1011], [12], [13, 62], [23], [1337], [991]]
Intersection: [[0, 7, 1337], [1, 1, 666], [2, 23], [4, 991]]
Intersection reduced to representatives: [0, 1, 2, 4]
Run Code Online (Sandbox Code Playgroud)