比较两个可能有边界或没有边界的范围

时间:2019-02-21 13:52:13

标签: if-statement language-agnostic logic

这个问题很简单,但是要想出一个不是数百行的斯法加蒂else-ifs解决方案就很难了。

有2个范围可能有边界,也可能没有边界。如果有边界,它们可能是包含边界的。

伪代码:

struct bound
{
    float val
    bool inclusive
}

struct range
{
    optional<bound> lower_bound
    optional<bound> upper_bound
}

例如,<3, 5](数字> 3和<= 5)将是range: { lower_bound: {3, false}, upper_bound: {5, true} },而[8,(数字> = 8)将是range: { lower_bound: { 8, true }, upper_bound: null }

给出2个范围,决定第一个范围与第二个范围的关系(相同,子集,超集,相交,不交集)(上面的示例范围是不交集的,因为任何值都不能都是<= 5和> = 8)

enum relation { identical, subset, superset, intersect, disjoint }

relation_first_to_second(range first, range second): relation
{
     // ???
}

问题在于,在编写函数时必须小心处理所有可能的极端情况,我制作了一个展示这些情况的示例图表(-表示没有限制)。我们可以假设范围始终是有效的,换句话说,我们可以假设(如果存在)A始终小于或等于B,X始终小于或等于Y(但我们不能假定以下两者之间的关系: XA / YB / XB / Y)。

lower upper   lower upper   relation first to second
  -     -       -     -      identical
  -     -       -     Y      superset
  -     -       X     -      superset
  -     -       X     Y      superset
  -     B       -     -      subset
  -     B       -     Y      B=Y: identical, B<Y: subset, B>Y superset
  -     B       X     -      B<X: disjoint, B>=X: intersect
  -     B       X     Y      B<X: disjoint, X<=B<=Y: intersect, B>Y: superset
  A     -       -     -      subset
  A     -       -     Y      A<=Y: intersect, A>Y: disjoint
  A     -       X     -      A=X: identical, A<X: superset, A>X: subset
  A     -       X     Y      A>Y: disjoint, X<=A<=Y: intersect, A<X: superset
  A     B       -     -      subset
  A     B       -     Y      Y<A: disjoint, A<=Y<=B: intersect, Y>B: subset
  A     B       X     -      X<A: subset, A<=X<=B: intersect, X>B: disjoint
  A     B       X     Y      this will be complex to check...

请注意,此图表未考虑inclusive


如果您有更好的实现范围的想法-不用客气,只是不要假设<=3<4是相同的,并且不要依赖未绑定范围可以使用整数的最小值/最大值(实际问题域更为通用)。我想不出任何更好的表示形式,而该类型由可能存在或不存在的2个边界(每个边界存储值以及是否包含)组成。


我正在寻找实现relation_first_to_second函数的代码(任何语言或伪代码)越短越好。这不是一个代码问题,但是我认为“最短的代码解决方案是最好的答案”与这个问题非常相关。

2 个答案:

答案 0 :(得分:2)

您对范围的表示是不完整的,因为它不允许人们区分正无穷大和负无穷大,因此将空范围表示为(+∞,-∞)。将+∞和-∞都添加到允许值列表中后,所有这些值突然都就位。

您现在可以比较端点并找到最小和最大的端点。如果两个端点具有相同的有限坐标并且在包含性上有所不同,则将其最小值和最大值都视为排他性会很方便。

现在,两个范围r1和r2的交集将是从[{'id': 1, 'indicator': [{'id': 4, 'name': 'Ind1_1'}, {'id': 5, 'name': 'Ind1_2'}, {'id': 6, 'name': 'Ind1_3'}], 'name': 'Res1', 'type': 'resource'}, {'id': 2, 'indicator': [{'id': 7, 'name': 'Ind2_1'}, {'id': 8, 'name': 'Ind2_2'}, {'id': 9, 'name': 'Ind2_3'}, {'id': 10, 'name': 'Ind2_4'}], 'name': 'Res2', 'type': 'service'}, {'id': 3, 'indicator': [{'id': 11, 'name': 'Ind3_1'}, {'id': 12, 'name': 'Ind3_2'}, {'id': 13, 'name': 'Ind3_3'}, {'id': 14, 'name': 'Ind3_4'}], 'name': 'Res3', 'type': 'service'}] max(r1.left, r2.left)的范围。此结果可以为空,等于min(r1.right, r2.right),等于r1,等于或两者都不是。这对应于您的不相交,子集,超集,相同和相交关系。

注意:两个空范围始终是相同的不相交,但是它们的表示可能不等于等于(空范围有很多表示)。如果希望“相同”谓词在空范围内正常工作,则需要单独检查。

这里有些草率地拼凑了Haskell:

r2

添加data Point = MinusInfinity | Finite Double Bool | PlusInfinity deriving (Eq, Ord, Show) data Range = Range { left :: Point , right :: Point } deriving (Eq, Show) min', max' :: Point -> Point -> Point min' (Finite p1 i1) (Finite p2 i2) | p1 == p2 = Finite p1 (i1 && i2) min' z1 z2 = min z1 z2 max' (Finite p1 i1) (Finite p2 i2) | p1 == p2 = Finite p1 (i1 && i2) max' z1 z2 = max z1 z2 intersection r1 r2 = Range (max' (left r1) (left r2)) (min' (right r1) (right r2)) 等是不重要的练习。

答案 1 :(得分:1)

让我们解决两个范围都对某种假设的命令式/面向对象语言具有边界的情况。

如果您愿意,假设我们已实现绑定比较以返回-1,0,1(使用飞船运算符<=>或由compare()函数代替)。

bound self <=> bound y
    return (self.val == y.val)
        ? (self.inclusive <=> y.inclusive) // assume that false < true
        : (self.val <=> y.val);

现在,如果我们进行测试:

ax = a <=> x;
by = b <=> y;

If ax < by then ab is superset of xy;
If ax > by then ab is subset of xy;
If ax + by == 0 then ab equals xy;

然后还有交集和分离的情况,如果没有其他测试我们就无法决定

bx = b <=> x;
ay = a <=> y;
If bx == ay then ab and xy are disjoint;
Else ab and xy intersect;

我想我们对于有限范围不能做太多事情。

现在,如果您引入+/-无限val或+/-无限边界,问题就解决了。

当然,对于无限边界,这意味着您必须处理所有比较,这可以通过<=>运算符重载或对于非静态类型语言的双重分派来实现,但这是一项容易的任务。

如果您坚持使用不能区分-infinity和+ infinity的表示形式,那么您将无法轻松进行比较b <=> xa <=> y,而不会引入其他if ...