2010-08-20 11 views
8

Estoy buscando una forma eficiente (en .NET), cómo encontrar si hay una secuencia de bytes en alguna lista de bytes y si hay alguna, índice donde comienza la primera.¿Cómo encontrar el índice de sublista en la lista?

Por ejemplo digamos que tengo:

var sequence = new List<byte> { 5, 10, 2 }; 
var listOne = new List<byte> { 1, 3, 10, 5, 10, 2, 8, 9 }; 
var listTwo = new List<byte> { 1, 3, 10, 5, 2, 10, 8, 9 }; 

y el resultado debe ser que mi secuencia es el índice de las 3 de la LISTONE y en el índice de -1 (. Es decir, que no está ahí) en el listTwo.

Por supuesto, puedo recorrer la lista int por int y de cada índice y buscar si los siguientes números coinciden con mi secuencia, pero ¿hay alguna forma más eficiente (por ejemplo, utilizando métodos de extensión)?

+1

Seguramente si la lista no está ordenada, ¿tendrá que iterar sobre cada elemento hasta encontrar la secuencia? El uso de métodos de extensión o Linq no puede aumentar mágicamente la eficiencia. –

+0

No creo que exista alguna lib de .NET con este tipo de extensión. Pero puedes crear el tuyo propio. –

+0

Tengo que agregar, que mi secuencia es bastante corta (pocos) pero las listas donde la busco son largas (miles de elementos) –

Respuesta

1

Sugeriría convertir cada List<int> en String y luego buscar usando String.IndexOf(sequence) para determinar dónde o si la secuencia está presente.

+1

Mmh Realmente dudo que esto aumente la eficiencia, porque tienes que crear cadenas de listas (con más uso de memoria y más computación). Seguro que facilitará las cosas, ya que no necesita escribir el código para buscar la subcadena. – digEmAll

+0

También me preocupa la eficiencia. Pero definitivamente sería más corto y tal vez legible. –

+0

Si crea un método de extensión y lo describe, también será abreviado y legible en lugar de usarlo. –

5

Esto es esencialmente el mismo problema que la búsqueda de subcadenas (de hecho, una lista donde el orden es significativo es una generalización de "cadena").

Afortunadamente, la informática ha considerado este problema con frecuencia durante mucho tiempo, por lo que se pone de pie sobre los hombros de los gigantes.

Eche un vistazo a la literatura. Algunos puntos de partida razonables son:

http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm

http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm

http://en.wikipedia.org/wiki/Rabin-karp

Aunque sólo el pseudocódigo en los artículos de Wikipedia es suficiente para el puerto de C# con bastante facilidad. Mire las descripciones del rendimiento en diferentes casos y decida qué casos es más probable que encuentre su código. (Estoy pensando que lo primero que dices sobre la lista de claves de búsqueda es corto).

+0

Gracias por los enlaces, me pregunto, si hay algún método implementado en.NET utilizando algunos de estos algoritmos, para ahorrar mi tiempo, antes de implementarlos yo mismo. –

+0

¡Es bastante probable que 'System.String.IndexOf' implemente uno de ellos! Está aplicando el mismo algoritmo a un tipo de datos con el que no se usa con tanta frecuencia, lo que reduce las posibilidades de encontrar una impl. Estoy seguro de que hay uno por ahí en alguna parte, pero encontrarlo es una cuestión diferente. –

4

Creo que la forma más limpia es crear un método de extensión genérica como esto:

public static int SubListIndex<T>(this IList<T> list, int start, IList<T> sublist) 
{ 
    for (int listIndex = start; listIndex < list.Count - sublist.Count + 1; listIndex++) 
    { 
     int count = 0; 
     while (count < sublist.Count && sublist[count].Equals(list[listIndex + count])) 
      count++; 
     if (count == sublist.Count) 
      return listIndex; 
    } 
    return -1; 
} 

que llaman de esta manera:

var indexOne = listOne.SubListIndex(0, sequence); 
var indexTwo = listTwo.SubListIndex(0, sequence); 

P. S. también puede comenzar desde un índice dado, si necesita buscar más ocurrencias de sublistas

+0

Eso es exactamente lo que estoy haciendo ahora. Pero como dijo Jon Hanna, hay formas más eficientes para la búsqueda de subconjuntos. Solo quiero saber si no me falta algo en .NET. –

+0

IMO esos algoritmos no son fácilmente aplicables a cadenas no char. Por ejemplo, boyer-moore requiere una matriz de tamaño alphabeth y para Int32 el tamaño de alphabeth es de 2^32. Rabin-karp usa hashing que para cadenas no reales podría ser bastante difícil de implementar. Probablemente, el único realmente utilizable es Knuth-Morris-Pratt, pero creo que no sería tan rápido ... – digEmAll

Cuestiones relacionadas