【问题标题】:How to compare two lists of rules?如何比较两个规则列表?
【发布时间】:2011-12-05 05:52:46
【问题描述】:

我需要比较两个格式为var -> integer 的规则列表是否不匹配。
确定是否有任何规则与 lhs 相同而 rhs 不同。

例如:

{a->3, b->1, c->4} ~ ??? ~ {a->3, b->1, c->4} = true
{a->3, b->1, c->4} ~ ??? ~ {a->3, b->2, c->4} = 假
{a->3, b->1, c->4} ~ ??? ~ {a->1, b->3, c->4} = 假
{a->3, b->1, c->4} ~ ??? ~ {c->4, d->8, e->9} = true
{a->3, b->1, c->4} ~ ??? ~ {d->8, e->9, f->7} = 真

在我的情况下,它们已经按 lhs 排序,并且所有 lhs 都是唯一的,如果它有助于实现尽可能简单的功能。

UPD:忘了一件事!列表可以有不同的长度。但似乎所有三个当前答案仍然有效。

【问题讨论】:

    标签: comparison wolfram-mathematica rules


    【解决方案1】:

    这是一个稍微概括的方法:

    In[24]:= check[lists__] := 
     And @@ (SameQ @@@ GatherBy[Join[lists], First])
    
    In[25]:= {
      {a -> 3, b -> 1, c -> 4}~check~{a -> 3, b -> 1, c -> 4}, 
      {a -> 3, b -> 1, c -> 4}~check~{a -> 3, b -> 2, c -> 4}, 
      {a -> 3, b -> 1, c -> 4}~check~{a -> 1, b -> 3, c -> 4}, 
      {a -> 3, b -> 1, c -> 4}~check~{c -> 4, d -> 8, e -> 9}, 
      {a -> 3, b -> 1, c -> 4}~check~{d -> 8, e -> 9, f -> 7}
      }
    
    Out[25]= {True, False, False, True, True}
    

    这个不要求元素是规则,它们可以是列表,或者几乎任何其他头部。它也应该适用于任意数量的输入。

    【讨论】:

      【解决方案2】:

      也许更简单

      check[a : {__Rule}, b : {__Rule}] :=  SameQ @@ Transpose[a /. b /. a /. Rule -> List]
      

      编辑

      这里有一个更深奥的版本,它的优点是完全高级,在某种意义上我们不需要知道规则的内部结构,只需要知道它们是如何作用的:

      checkAlt[a : {__Rule}, b : {__Rule}] := # === (# /. #) &[a /. b /. a]
      

      编辑 2

      好吧,让我再扔一个,只是为了好玩:

      check1[{a__Rule}, {b__Rule}] := SameQ @@ ({a, b} /. {{a, b}, {b, a}})
      

      【讨论】:

      • @Nakilon 我们的想法是我们在a 的 l.h.s 上遵循来自b 的规则。这假定a 的右上方没有变量。例如,如果a{c->1,d->2,e->3},而b{c->1,d->3,f->4},那么您将得到a/.b 这个:{1->1,2->3,e->4}。我们现在与a 一起行动,以便那些不在b l.h.s 中的变量。也会被替换。然后你会得到{1->1,2->3,4->4}。为了使规则集相同,l.h.s.和 r.h.s of 规则必须相同。这由其余代码检查,其中规则首先转换为子列表。
      • @Alexey 确实,我的版本不是很通用。我使用的是 OP 的规范:规则被限制为 var->int 的形式,但是当 r.h.s. 上没有变量时,它也适用于所有情况
      • @Alexey 如果我们得到一个像{1->1,2->2} 这样的空闲规则列表,那么当我们对其自身进行操作时,它不会改变。如果我们有一个列表,其中一些规则不是空闲的,比如{1->1,2->3,3->3},那么当我们对其自身采取行动时,列表将必然发生变化(#/.#),这似乎也很容易看,因为那些不同的相同 lhside 将被它们的 rh 替换边,给出一个不同的规则列表。
      • @Leonid 哎呀!此行为是“更多信息”字段中的documented。很抱歉造成混乱。
      • @Alexey 哦,但它是,虽然在教程而不是功能页面中:reference.wolfram.com/mathematica/tutorial/…
      【解决方案3】:

      这是另一个解决方案:

      In[12]:= check[a:{__Rule}, b:{__Rule}] := FilterRules[a, b] === FilterRules[b, a]
      
      In[18]:= {{a -> 3, b -> 1, c -> 4}~check ~ {a -> 3, b -> 1, c -> 4} ,
       {a -> 3, b -> 1, c -> 4}~check ~ {a -> 3, b -> 2, c -> 4},
       {a -> 3, b -> 1, c -> 4}~check ~ {a -> 1, b -> 3, c -> 4},
       {a -> 3, b -> 1, c -> 4}~check ~ {c -> 4, d -> 8, e -> 9},
       {a -> 3, b -> 1, c -> 4}~check ~ {d -> 8, e -> 9, f -> 7}}
      
      Out[18]= {True, False, False, True, True}
      

      (这取决于选项列表已经排序的事实。)

      【讨论】:

      • 除了大小之外,这个解决方案在我的数据上比其他两个快 3 倍。
      • @Nakilon 如果速度是个问题,请在 r.h.s. 上包装规则。 Dispatch 中的 /. - 这应该加快代码速度,无论是对于我的版本还是 @Heike 的。
      【解决方案4】:

      你可以做类似的事情

      check[{a__Rule}, {b__Rule}] := 
       Module[{common = Intersection[{a}[[All, 1]], {b}[[All, 1]]]},
        SameQ[common /. {a}, common /. {b}]]
      

      然后

      check[{a -> 3, b -> 1, c -> 4}, {a -> 3, b -> 1, c -> 4}]
      check[{a -> 3, b -> 1, c -> 4}, {a -> 3, b -> 2, c -> 4}]
      check[{a -> 3, b -> 1, c -> 4}, {a -> 1, b -> 3, c -> 4}]
      

      产量

      True
      False
      False
      

      【讨论】:

      • +1 这正是我想出的方法(但比你晚了半小时!)。
      • +1 通过将BlankSequence (__) 替换为BlankNullSequence (___): check[{a___Rule}, {b___Rule}] := ...,可以很容易地将这个解决方案推广到空规则集。
      • check[{a__Rule}, {b__Rule}] :=check[a, b] := 有什么区别?
      • @Nakilon 请阅读相应的文档页面:“Making Definitions for Functions”、“Blank (_)”、“BlankSequence (__)”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多