Как сравнить два списка правил? - PullRequest
9 голосов
/ 11 октября 2011

Мне нужно сравнить два списка правил формы 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} = false
{ a-> 3 , b-> 1 , c-> 4} ~ ???~ { a-> 1 , b-> 3 , c-> 4} = false
{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} = true

В моем случае они уже отсортированы по lhs и всем lhs уникальны, если могут помочь сделать максимально простую функцию.

UPD: забыл одну вещь!Списки могут быть разной длины.Но кажется, что все три текущих ответа все еще действительны.

Ответы [ 4 ]

7 голосов
/ 11 октября 2011

Возможно, проще

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

EDIT

Вот еще более эзотерическая версия, которая имеет преимущество в том, что она полностью высокого уровня в том смысле, что нам не нужно ничего знать о внутренней структуре правил, только о том, как они действуют:

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

РЕДАКТИРОВАТЬ 2

Хорошо, позвольте мне добавить еще один, просто для удовольствия:

check1[{a__Rule}, {b__Rule}] := SameQ @@ ({a, b} /. {{a, b}, {b, a}})
7 голосов
/ 11 октября 2011

Вот еще одно решение:

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}

(Это зависит от того, что списки опций уже отсортированы.)

7 голосов
/ 11 октября 2011

Вы могли бы сделать что-то вроде

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
2 голосов
/ 12 октября 2011

Вот немного обобщенный подход:

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}

Этот элемент не требует, чтобы элементы были правилами, они могли быть списками или почти любым другим заголовком. Он также должен работать на любом количестве входов.

...