2010-10-20 6 views
8

si tengo una gran matriz de cadenas de JavaScript que tiene más de 10 000 elementos, ¿cómo puedo buscar rápidamente a través de ella?optimizar la búsqueda a través de una gran matriz js string?

Ahora mismo tengo una matriz de cadenas javascript que almacena la descripción de un trabajo, y yo "M que permite al usuario filtro dinámico de la lista devuelta a medida que escribe en un cuadro de entrada.

Así que decir que tengo una matriz de cadenas de este modo:
var descArr = {"flipping burgers", "pumping gas", "delivering mail"};

y el usuario desea buscar:? "p"

¿Cómo voy a ser capaz de buscar una matriz de cadenas que tiene 10000 + descripciones en ella rápidamente Obviamente, no puedo ordenar la matriz de descripción ya que son descripciones, por lo que la búsqueda binaria está desactivada. Y dado que el usuario puede buscar por "p" o "pi" o cualquier combinación de letras, esta búsqueda parcial significa que no puedo usar matrices asociativas (es decir, searchDescArray["pumping gas"]) para acelerar la búsqueda.

¿Alguna idea a alguien?

+1

¿Desea hacer coincidir la búsqueda al principio de las cadenas o dentro de las cadenas? Si el usuario busca "p", ¿debería incluir "voltear hamburguesas" en el resultado? – Guffa

+1

descArr no es una matriz sino un objeto literal. –

+0

@guffa, Sí, si el usuario busca "p", debe incluir "voltear hamburguesas" en el resultado. Encuentro que la mayor desaceleración en este momento es la búsqueda real. Actualmente tengo un forloop que itera sobre la matriz y hace esta comparación: if (descArray [i] .search ("P"))> -1) {// return result} – TriFu

Respuesta

18

Como los motores de expresiones regulares en los navegadores actuales están volviendo loco en términos de velocidad, ¿qué hay de hacerlo de esa manera? En lugar de una matriz, pase una cuerda gigante y separe las palabras con un identificador. Ejemplo:

  • cadena "flipping burgers""pumping gas""delivering mail"
  • Regex: "([^"]*ping[^"]*)"

Con el interruptor /g para el mundial de obtener todos los partidos. Asegúrese de que el usuario no busque su separador de cadenas.

Usted puede incluso agregar un id en la cadena con algo como:

  • cadena "11 flipping burgers""12 pumping gas""13 delivering mail"
  • Regex: "(\d+) ([^"]*ping[^"]*)"

  • Ejemplo: http://jsfiddle.net/RnabN/4/ (30,000 cuerdas, límite de los resultados a 100)

+0

El rendimiento no se trata tanto de navegadores modernos como de hardware y hábitos de usuario. En la vida real, 2GB de RAM para la computadora de un usuario promedio da un resultado diferente cuando se compara con una máquina de un desarrollador experimentado. Las personas de TI mantienen sus computadoras en buena forma. – Saul

+0

Los tiempos de ejecución de expresión regular modernos son casi tan rápidos como un programa de C++ precompilado. Hay mundos de rendimiento entre el viejo JavaScript (Firefox 2/Netscape/Internet Explorer) y las nuevas implementaciones Just-In-Time. JavaScript en una PC promedio con Chrome corre varias veces más rápido que JavaScript en una PC de alta calidad con Internet Explorer. – sod

+0

Esto funcionó exactamente como se anuncia. Gracias. – Saltymule

1

Puede que esta no sea una respuesta para usted, ya que estoy haciendo algunas suposiciones sobre su configuración, pero si tiene un código del lado del servidor y una base de datos, sería mucho mejor hacer una llamada AJAX para obtener el reduzca la lista de resultados y use una base de datos para filtrar (ya que son muy buenos en este tipo de cosas).

Además del beneficio de la base de datos, también se beneficiaría al no generar tantos datos (10000 variables) en un front-end basado en web; si solo devuelve los que necesita, entonces ahorrará un poco de ancho de banda

+0

Una base de datos necesitaría un índice de texto completo para ser adecuado para este trabajo, eso no es algo que las bases de datos implementen de manera predeterminada, ya que cuesta mucho almacenamiento/memoria . Todavía puede ser más rápido usar una base de datos normal simplemente porque ejecuta código mucho más rápido que el peor navegador IE6, pero si tiene que manejar una gran cantidad de usuarios, entonces debe tener un índice especializado. – aaaaaaaaaaaa

+0

@eBusiness: no se necesitaría un índice de texto completo para esto. En SQL Server, una consulta con un título WHERE como 'P%' aún sería SARGable y usaría un índice en esta columna si hubiera uno presente. También es más rápido porque no está transmitiendo todos los 10000 a través del cable al cliente antes del procesamiento, solo la lista de reducción. – Paddy

+0

Después de pensar durante 3 años, ¿esa es tu mejor réplica?% P% no es sargable, y creo que eso es lo que quería el asker. – aaaaaaaaaaaa

0

Sugiero probar una función JS preparada, por ejemplo, el autocomplete de jQuery. Es rápido y tiene muchas opciones para configurar.

Mira la jQuery autocomplete demo

+0

Hola medopal, gracias por la sugerencia, pero la autocompleta de JQuery solo es rápida cuando hay relativamente pocas entradas, cuando en el orden de 10K + también se vuelve lenta – TriFu

4

No hay forma de acelerar un n inicial búsqueda en matriz sin realizar algunos cambios. Puede acelerar las búsquedas consecutivas almacenando los resultados en caché y asignándolos dinámicamente a patrones.

1.) Ajuste su formato de datos. Esto hace que las búsquedas iniciales sean algo más rápidas. Básicamente, precache.

var data = { 
    a : ['Ant farm', 'Ant massage parlor'], 
    b : ['Bat farm', 'Bat massage parlor'] 
    // etc 
} 

2.) Configurar la mecánica de la memoria caché.

var searchFor = function(str, list, caseSensitive, reduce){ 
    str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace 
    var found = []; 
    var reg = new RegExp('^\\s?'+str, 'g' + caseSensitive ? '':'i'); 
    var i = list.length; 
    while(i--){ 
     if(reg.test(list[i])) found.push(list[i]); 
     reduce && list.splice(i, 1); 
    } 
} 

var lookUp = function(str, caseSensitive){ 
    str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace 
    if(data[str]) return cache[str]; 
    var firstChar = caseSensitive ? str[0] : str[0].toLowerCase(); 
    var list = data[firstChar]; 
    if(!list) return (data[str] = []); 
    // we cache on data since it's already a caching object. 
    return (data[str] = searchFor(str, list, caseSensitive)); 
} 

3.) Utilice la siguiente secuencia de comandos para crear un objeto precaché. Te sugiero que lo ejecutes una vez y uses JSON.stringify para crear un objeto de caché estático. (O hacerlo en el backend)

// we need lookUp function from above, this might take a while 
var preCache = function(arr){ 
    var chars = "abcdefghijklmnopqrstuvwxyz".split(''); 
    var cache = {}; 
    var i = chars.length; 
    while(i--){ 
     // reduce is true, so we're destroying the original list here. 
     cache[chars[i]] = searchFor(chars[i], arr, false, true); 
    } 
    return cache; 
} 

Probablemente un poco más código, entonces lo esperado, pero optimización de su rendimiento y no viene de forma gratuita.

+0

Estoy intrigado por este mecanismo de búsqueda. Sin embargo, estoy confundido de por qué solo precache cada letra? ¿Este método también almacena en caché palabras completas? Supongamos que quiere buscar 'bat' en una matriz de 20,000 cadenas. – mesqueeb

1

No puedo reproducir el problema, he creado una implementación ingenua, y la mayoría de los navegadores realizan la búsqueda entre 10000 15 cadenas de caracteres en un solo dígito de milisegundos. No puedo probar en IE6, pero no lo creo más de 100 veces más lento que los navegadores más rápidos, que aún serían prácticamente instantáneos.

Inténtelo usted mismo: http://ebusiness.hopto.org/test/stacktest8.htm (Tenga en cuenta que el tiempo de la creación no es relevante para el tema, que está ahí sólo para obtener algunos datos para trabajar.)

Una cosa que podría hacer el mal está tratando de hacer que todo resultados, eso sería un trabajo enorme cuando el usuario solo ingresó una sola letra o una combinación de letras común.

Cuestiones relacionadas