给定若干个条件,怎么判断这些条件彼此互斥

2021-07-14 11:23:37 +08:00
 murmur

需求是流程编辑器,想要检查用户设定的分支是否冲突

比如左边的分支是 A>80 右边的分支理论上应该是 A<=80,但是不要是右边分支是 A>60,或者是 B>80 这种没法做唯一性的解

见过其他的解决方案,都是设定默认分支,当程序也不知道怎么走的时候,就走默认分支

类似的可以扩展到多个分支,多个条件

如果感觉不靠谱,可以限制为单条件,也就是说没有[a, b]这样的左右区间比较

除了手写 if-else 判断有没有什么优雅方法

2026 次点击
所在节点    程序员
12 条回复
wutiantong
2021-07-14 11:53:59 +08:00
给分支附加上优先级(排序),按优先级从高到低依次检查,遇到满足的就 break,全都不满足就走最后的 default 。
如果按这样做就不存在“冲突”了。

对于你描述的情况,可以引用集合概念,每个分支的条件相当于对应一个子集,“不冲突”相当于要求所有的子集两两不相交。而默认分支应该代表所有子集之外的补集。
aguesuka
2021-07-14 12:36:00 +08:00
假设流程是没有环的, 而且分支和流程之间没有依赖关系.

有规则:
大写字母记作断言, 小写字母记作流程.

1. A -> a -> B -> b 记作 "如果 A 为真, 那么执行 a, 然后如果 B 为真, 那么执行 b".
这个流程可以简化成两个等价的流程 A -> a; A -> B -> b (有序). 也就是"如果 A 成立, 那么执行 a, 然后 如果 A 且 B, 那么执行 b"
2. A -> (B -> b Else C -> c) 记作 "如果 A 为真, 那么如果 B 那么 b, 如果非 B 且 C 那么 c", 等价于 A -> B -> b; A -> !B -> C -> c
3. A & B -> c 记作 "如果 A 为真且 B 为真, 那么执行 c" , 等价于 A -> B -> c.
4. A | B -> c 记作 "如果 A 为真或 B 为真, 那么执行 c " 等价于 A -> c; B ->c.

根据以上规则, 如果流程没有环, 那么可以将流程的有向无环图化简成它的所有可达路径. 这样只须实现可达路径上的冲突判断即可. 例如问题主干就对应规则 4.

假如流程之间有依赖关系, 规则比这里的复杂, 但也类似. 而流程是有环的情况, 直觉上应该是不可判定问题, 除非加上一些限制.
murmur
2021-07-14 12:42:30 +08:00
@aguesuka 感觉是我描述错了么,我这个是编辑器用的,不是流程执行用的

比如 3 个分支,1.A>50 2.30<=A<=50 3.A<30 属于合理设计,但是如果第三个条件设置成 A<10 或者 B<30 就有瑕疵,因为这 3 个分支没有覆盖所有的可能条件

简单点说就是要这几个条件的 AB 能覆盖整个数值区间,任何一个数来了都是 3 个条件中唯一确定的,而不是 1 对 2 可能也对
aguesuka
2021-07-14 12:56:58 +08:00
一样的
比如 1. (A > 50 | B > 50) 2. (B <= 50 & A > 50) 3. (A <= 50) 等价于

A > 50 -> B <= 50 -> A > 50 -> A <= 50
B > 50-> B <= 50 -> A > 50 -> A <= 50

可以看见两种情况下 A 都完整覆盖了, 但第一种情况下 B 没有完整覆盖
aguesuka
2021-07-14 13:34:06 +08:00
我知道你问的啥了, 我把"右边分支是 A>60,或者是 B>80" 理解成"右边分支是 (A>60,或者是 B>80)" 而你的意思是 "右边分支是 A>60,或者右边分支是 B>80 ".

如果是数字的话就把判断的区间按照区间的下限排序, 然后判断这个数组是不是连续的, 并覆盖了所有数.

例如: 1.A>50 2.30<=A<=50 3.A<10. 转换成区间 (50, null), [30, 50], (null, 10) 然后按下限排序, 刚好反过来 (null, 10), [30, 50] ,(50, null) 第一个区间的上限是 10, 第二个区间的下限是 30, 所以不连续.
PonysDad
2021-07-14 13:39:04 +08:00
形式化后进行命题逻辑演算。具体回去翻翻离散数学命题逻辑部分。
TomatoYuyuko
2021-07-14 13:41:25 +08:00
可能我理解有误。咱们能不能这样,咱们不纠结于“条件”设定本身,而是在每次应用这个规则的时候直接取反不就可以了吗
JerryCha
2021-07-14 13:57:29 +08:00
按我的理解,可能问后端流程怎么跑更有效,校验时取几个值试算一下。
kilasuelika
2021-07-14 14:20:28 +08:00
有种区间树的数据结构,可以用来查询值是否在区间集合内。
有现成的就不要自己来搞。
no1xsyzy
2021-07-15 09:32:50 +08:00
先问几个最难搞的问题
1. NaN 怎么办?
NaN > 80 # false
NaN <= 80 # false

2. 是否存在非简单判断条件?如何判断已竭?
isexpression(e)
isfunction(e)

3. 存在副作用?
dice('5d20') > 80
dice('5d20') <= 80
WhereverYouGo
2021-07-15 10:01:32 +08:00
@JerryCha #8 头像 JK 是什么鬼 😳
murmur
2021-07-15 10:50:21 +08:00
楼上的兄弟就不一一回了
1 、离散数学不是科班真的看不懂
2 、说数据排序和区间树的貌似是不错的思路
3 、因为有多个分支,所以简单设置 A 和!A 不够
4 、这个只需要部分校验,不需要做到尽善尽美,不过如果纯数字简单大小区间都判定不了就有点弱了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/789435

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX