Haciendo una alternativa más rápida para {PatternSequence [1, PatternSequence [2, 3 ..] ..] ..}

Sep 23 2020

Necesito mejorar un patrón o cambiar de enfoque.

Se describe mejor con un ejemplo

Para una jerarquía / orden dado por una lista, por ejemplo:

order = {1, 2, 3} 

y una lista:

list = {
  1, 2, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3,
   3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3
  }

Necesito verificar que listcoincida con una secuencia definida por order:

MatchQ[list, {PatternSequence[1, PatternSequence[2, 3 ..] ..] ..}]

Este patrón escala muy mal, ya que no se termina de evaluar.

La función solo debe tomar listcomo argumento, considerar el orden constante. El patrón no necesita construirse automáticamente.

Respuestas

10 LeonidShifrin Sep 23 2020 at 22:53

Lo siguiente parece funcionar para mí, a menos que me falte algo:

ClearAll[match]
match[{}][{}] := True;
match[{fst_, rest___}][l_List] :=
  And @@ Map[
    Replace[
      match[{rest}][#], 
      False :> Return[False, Map]
    ]&,
    Replace[
      ReplaceList[
        l, 
        {
          {___, fst, middle : Except[fst] ..., fst, ___} :> {middle}, 
          {___, fst, r : Except[fst] ...} :> {r}
        }
      ],
      {} -> False
    ]
 ]

(La pieza Replace[match[{rest}][#], False :> Return[False, Map]]&es opcional y, en principio, puede sustituirse por solo match[{rest}]).

Ejemplo:

match[{1, 2, 3}][list] // AbsoluteTiming
match[{1, 2, 3}][Append[list, 1]] // AbsoluteTiming

(* {0.00038, True} *)

(* {0.000383, False} *)
10 C.E. Sep 24 2020 at 02:44

Esta solución intenta reducir la lista a una lista de un solo tipo de elementos; si tiene éxito, la lista sigue el patrón prescrito.

MatchQ[
  SequenceReplace[
   SequenceReplace[list, {2, 3 ..} :> x],
   {1, x ..} :> y
   ],
  {y ..}
  ] // AbsoluteTiming

{0.0019598, True}

Esta es una versión de la máquina de estado que Daniel recomendó en un comentario:

f[1, 2] = 2;
f[2, 3] = 3;
f[3, 2] = 2;
f[3, 1] = 1;
f[3, 3] = 3;
f[_, _] := Throw[False]

And[
  First[list] == 1 && Last[list] == 3,
  Catch[Fold[f, list]; True]
] // AbsoluteTiming

{0.0000455, True}