Как сравнить два списка правил?

#comparison #wolfram-mathematica #rules

#сравнение #wolfram-mathematica #Правила

Вопрос:

Мне нужно сравнить два списка правил формы 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: забыл одну вещь! Списки могут быть разной длины. Но, похоже, все три текущих ответа все еще действительны.

Ответ №1:

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

 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}
  

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

Комментарии:

1. В дополнение к размеру, это решение в 3 раза быстрее для моих данных, чем два других.

2. @Nakilon Если скорость является проблемой, перенесите правила в r.h.s. из /. in Dispatch — это должно ускорить код, как для моей версии (версий), так и для @Heike.

Ответ №2:

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

 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 Это именно тот подход, который я придумал (но через полчаса после вас!).

2. 1 Это решение можно легко обобщить для пустых наборов правил, заменив BlankSequence ( __ ) на BlankNullSequence ( ___ ): check[{a___Rule}, {b___Rule}] := ... .

3. В чем разница между check[{a__Rule}, {b__Rule}] := и check[a, b] := ?

4. @Nakilon Пожалуйста, прочтите соответствующие страницы документации: » Создание определений для функций «, » Blank ( _ ) «, » BlankSequence ( __ ) «.

Ответ №3:

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

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

Редактировать

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

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

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

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

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

Комментарии:

1. @Nakilon Идея в том, что мы действуем с правилами из b l.h.s of a . Это предполагает, что в r.h.s нет переменных 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} . Чтобы наборы правил были одинаковыми, стандартные и стандартные правила должны быть одинаковыми. Это проверяется остальной частью кода, где правила сначала преобразуются во вложенные списки.

2. @Alexey Действительно, моя версия не очень общая. Я использовал спецификацию OP: правила ограничены формой var->int , но это будет работать также во всех случаях, когда в r.h.s нет переменных.

3. @Alexey Если мы получим список таких незанятых правил {1->1,2->2} , то он не изменится, когда мы будем действовать с ним самостоятельно. Если у нас есть список, в котором некоторые правила не простаивают, как, скажем {1->1,2->3,3->3} , тогда список обязательно изменится, когда мы будем действовать с ним с помощью функции itself ( #/.# ) , что также кажется довольно простым для просмотра, потому что те же самые lh.стороны, которые отличаются, будут заменены их rh. сторонами, предоставляя другой список правил.

4. @Leonid Ой! Это поведение задокументировано в поле «Дополнительная информация». Извините за путаницу.

5. @Alexey О, но это так, хотя и в учебном пособии, а не на странице функций: ссылка. wolfram.com/mathematica/tutorial /…

Ответ №4:

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

 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}
  

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