Supongamos que tengo una matriz de objetos javascript que se ve así:
[ { "title": "The Great Peace", "copyversion": 1 }, { "title": "History of World War II", "copyversion": 1 }, { "title": "Crime and Punishment", "copyversion": 2 }, { "title": "War and Peace", "copyversion": 2 } ]Ahora, supongamos que tengo una cadena de búsqueda, como "Guerra" o "y". Quiero obtener una matriz de objetos donde "título" contenga la cadena de búsqueda (sin distinción entre mayúsculas y minúsculas), pero TAMBIÉN quiero incluir valores hermanos con valores de "versión de copia" coincidentes.
Por ejemplo:
La cadena de búsqueda de "Excelente" debería arrojar el siguiente resultado, porque aunque "Historia de la Segunda Guerra Mundial" no tiene "Excelente", coincide con la versión copiada de algo que sí lo tiene.
[ { "title": "The Great Peace", "copyversion": 1 }, { "title": "History of World War II", "copyversion": 1 } ]Otro ejemplo:
La cadena de búsqueda de "Paz" produciría la matriz original. Se incluye "Historia de la Segunda Guerra Mundial" porque tiene el mismo valor de copia que "La gran paz", y se incluye "Crimen y castigo" porque tiene el mismo valor de copia que "Guerra y paz".
[ { "title": "The Great Peace", "copyversion": 1 }, { "title": "History of World War II", "copyversion": 1 }, { "title": "Crime and Punishment", "copyversion": 2 }, { "title": "War and Peace", "copyversion": 2 } ]Si no se encuentran coincidencias, resultará una matriz vacía.
Estoy buscando una forma razonablemente rápida de hacer esto. Estoy bien con javascript puro o una biblioteca como lodash.
Esa es mi solución simple y legible. Espero que sea útil para usted
const books = [ { "title": "The Great Peace", "copyversion": 1 }, { "title": "History of World War II", "copyversion": 1 }, { "title": "Crime and Punishment", "copyversion": 2 }, { "title": "War and Peace", "copyversion": 2 } ]; const findBooks = (titlePart) => { const regexp = new RegExp(`${titlePart}`, 'i'); const resultSet = new Set(); const copyVersionsSet = new Set(); // Find all books which has titlePart in title for (const book of books) { if (regexp.test(book.title)) { resultSet.add(book); copyVersionsSet.add(book.copyversion); } } // Find all books which has same copyversion as found books for (const book of books) { if (copyVersionsSet.has(book.copyversion)) { resultSet.add(book); } } return [...resultSet]; } console.log(findBooks('hIsToRy'));La solución contiene dos partes:
La primera parte puede optimizarse; no tenemos que eliminar los duplicados.
const a = [ { "title": "The Great Peace", "copyversion": 1 }, { "title": "History of World War II", "copyversion": 1 }, { "title": "Crime and Punishment", "copyversion": 2 }, { "title": "War and Peace", "copyversion": 2 } ]; const copyFinder = (word, arr) => { const rx = new RegExp(`${word}`, 'i'); const versions = arr.reduce((collector, value) => { if(rx.test(value.title) && collector.indexOf(value.copyversion) === -1) { collector.push(value.copyversion); } return collector; }, []); if(versions.length === 0) { return []; } return arr.filter(x => versions.indexOf(x.copyversion) > -1); } console.log(copyFinder('History', a));Aquí hay un enfoque:
const findMatches = (books = []) => ( search = "", lc = search .toLowerCase (), matches = new Set (books .filter (({title}) => title .toLowerCase () .includes (lc))), versions = new Set ([...matches] .map (({copyversion}) => copyversion)) ) => books .filter ((book) => matches .has (book) || versions .has (book .copyversion)) const books = [{"title": "The Great Peace", "copyversion": 1}, {"title": "History of World War II", "copyversion": 1}, {"title": "Crime and Punishment", "copyversion": 2}, {"title": "War and Peace", "copyversion": 2}] console .log ('crime: ', findMatches (books) ('crime')) console .log ('great: ', findMatches (books) ('great')) console .log ('war: ', findMatches (books) ('war')) .as-console-wrapper {max-height: 100% !important; top: 0}Tomamos la versión en minúsculas de la cadena de búsqueda, la usamos para filtrar la lista a aquellos con títulos coincidentes, almacenándolos como un Conjunto, luego asignándolos a sus versiones, almacenándolos nuevamente como un Conjunto y finalmente filtrando la lista original de libros para seleccionar aquellos en ese conjunto de coincidencias o cuyas versiones están en la versión uno.
Aunque elijo trabajar en este estilo, usando parámetros predeterminados en lugar de variables locales cuando sea factible, existe un posible inconveniente si findMatches (books) se usa de ciertas maneras, como pasar a map . Si eso es una preocupación, esta versión hace lo mismo de una manera un poco más compleja, sin esos problemas potenciales, ya que los únicos parámetros que conoce son los books y search :
const findMatches = (books = []) => (search = "") => (( lc = search .toLowerCase (), matches = new Set (books .filter (({title}) => title .toLowerCase () .includes (lc))), versions = new Set ([...matches] .map (({copyversion}) => copyversion)) ) => books .filter ((book) => matches .has (book) || versions .has (book .copyversion)))()