2011-01-11 8 views
5

Por ejemplo: Tengo gama¿Cómo determinar que una matriz es una parte de otra?

var src = new byte[] {1, 2, 3, 4, 5}; 
var tag = new byte[] {3, 4}; 

que saben método rápido para encontrar el índice de la matriz de la etiqueta? necesito algo de la siguiente manera:

int FindIndexOfSeq(byte[] src, byte[] sequence); 

una secuencia puede estar en más de un momento en src.

Solución: How to find index of sublist in list?

+1

posible duplicado http://stackoverflow.com/questions/3529727/how-to-find-index-of-sublist-in-list – nan

+2

Esto no es un problema fácil de resolver de manera eficiente. La búsqueda ingenua y fácil de implementar es el peor caso de 'O (nm) '. Puede mejorar sustancialmente (por ejemplo, Boyer-Moore), pero no es fácil. http://en.wikipedia.org/wiki/String_searching_algorithm#Single_pattern_algorithms – Ani

+0

¿Solo el índice de la primera aparición? –

Respuesta

1
int FindIndexOfSeq<T>(byte[] src, byte[] tag) 
{ 
    Int32 tagCount = tag.Count();    

    // If `tag` is not empty and `src` contains `tag` 
    if (tagCount > 0 && src.Intersect(tag).Count() == tagCount) 
    { 
     // Find index of first element in `tag` 
     Int32 tagStartIndex = Array.IndexOf(src, tag.First()); 

     // Get the matching slice of `tag` from `src` 
     var newSrc = src.Skip(tagStartIndex).Take(tag.Count()).ToList(); 

     // Zip them together using their difference 
     var sum = Enumerable.Zip(tag, newSrc, (i1, i2) => Convert.ToInt32(i2 - i1)).Sum(); 

     // If total of their differences is zero, both sequences match 
     if (sum == 0) 
     { 
      // return starting index of `tag` in `src` 
      return tagStartIndex; 
     } 
    } 

    // return `Not Found` 
    return -1; 
} 
+0

¿No se equivocaría si src es {1, 2, 3, 3, 4, 5} y la etiqueta es {3, 4}? –

2

Aquí es una manera de obtener el índice del

for (int i = 0; i < (src.Length - tag.Length); i++) 
{ 
    if (tag.SequenceEqual(src.Skip(i).Take(tag.Length))) 
     Console.WriteLine("It's at position " + i); 
} 

Por desgracia, es muy lento.

Si lo que desea es saber si todos los artículos en tag se pueden encontrar en src (en cualquier orden), entonces

var src = new byte[] { 1, 2, 3, 4, 5 }; 
var tag = new byte[] { 4, 3 }; 

if (src.Intersect(tag).Count() == tag.Length) 
    Console.WriteLine("tag can be found in src!"); 
+0

No, necesito saber el índice donde comienza la secuencia. –

+0

lo suficientemente inteligente. +1 – deadlock

+0

Jonas, en tu muestra tienes el orden incorrecto de bytes en la matriz de etiquetas. –

2

Lo mejor que se puede conseguir es O (m), pero que poco compleja implementación. Si satisface con una solución que tiene O (m * n) como el peor caso, puede ir con la solución a continuación. Si sus secuencias están ordenadas y el ítem inicial en la matriz tag solo está presente una vez en src, esto también dará como resultado O (m).

class Program 
{ 
    static void Main(string[] args) 
    { 
     var src = new byte[] { 1, 2, 3, 4, 5 }; 
     var tag = new byte[] { 3, 4 }; 
     var index = FindIndexOfSeq(src, tag); 
     Console.WriteLine(index); 
     Console.ReadLine(); 
    } 
    static int FindIndexOfSeq<T>(T[] src, T[] seq) 
    { 
     int index = -1; 
     for (int i = 0; i < src.Length - seq.Length + 1; i++) 
     { 
      bool foundSeq = true; 
      for (int j = 0; j < seq.Length; j++) 
      { 
       foundSeq = foundSeq && src[i + j].Equals(seq[j]); 
      } 
      if (foundSeq) 
      { 
       index = i; 
       break; 
      } 
     } 
     return index; 
    } 
} 

asumí la secuencia tiene que ser en ese orden y sólo han compilado en Firefox, así que no sé si funciona :). Además, lo hice genérico para que maneje cualquier tipo de matrices, no solo bytes.

ACTUALIZACIÓN: El código actualizado se compila y funciona ... o mi simple prueba funcionó.

+0

* Puedes * mejorar en 'O (nm)', de hecho es posible hacerlo en 'O (n)'. Ejemplo: Boyer-Moore. http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm – Ani

+0

Tienes razón ... Actualicé esa parte e incluí un programa simple. Además, estás en lo correcto con el O (n), pero parece un algoritmo mucho más complicado. ¿Es más rápido en juegos pequeños? Creo que hay una pequeña transacción allí. Si su secuencia se parece a la que proporcionó, dará como resultado O (n + m). –

+0

Sí, estoy de acuerdo en implementar cualquiera de esos es posiblemente excesivo para los usos más comunes. Pero aún así me deshace de "Lo mejor que puedes obtener es O (m * n)"; es un poco engañoso. – Ani

Cuestiones relacionadas