过滤 javascript 中的对象数组,其中兄弟项匹配公共键值

filter an array of objects in javascript, with siblings that match on a common key value

假设我有一个 javascript 对象数组,如下所示:

[
    {
        "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
    }
]

现在,假设我有一个搜索字符串,例如“War”或“and”。我想获取一个对象数组,其中“title”包含搜索字符串(不区分大小写),但我还想包含任何具有匹配“copyversion”值的同级值。

例如:

“Great”的搜索字符串应该会产生以下结果,因为即使“History of World War II”中没有“Great”,它也与包含“Great”的内容的副本匹配。

[
    {
        "title": "The Great Peace",
        "copyversion": 1
    },
    {
        "title": "History of World War II",
        "copyversion": 1
    }
]

另一个例子:

搜索字符串“Peace”将产生原始数组。收录《世界史WarII》是因为它与《太平盛世》具有相同的copyversion值,收录《罪与罚》是因为它与《War与和平》具有相同的copyversion “

[
    {
        "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
    }
]

如果未找到匹配项,则会生成一个空数组。

我正在寻找一种合理的快速方法来执行此操作。我可以使用纯 javascript 或像 lodash 这样的库。

解决方案包含两部分:

  1. 找到所有匹配的对象并收集它们的副本版本。不要重复存储。
  2. return 具有相应副本版本的所有对象。

可以优化第一部分 - 我们不必删除重复项。

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));

这是我的简单易读的解决方案。希望对你有用

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'));

这是一种方法:

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}

我们采用 lower-case 版本的搜索字符串,使用它来过滤列表以找到具有匹配标题的列表,将它们存储为一个集合,然后将它们映射到它们的版本,再次存储为一个集合,最后将原始书籍列表过滤为 select 匹配集中的书籍或版本在第一版中的书籍。

虽然我选择以这种方式工作,在可行的情况下使用默认参数代替局部变量,但如果以某些方式使用 findMatches (books),则有可能 down-side,例如传递给 map。如果这是一个问题,这个版本以稍微复杂的方式做同样的事情,没有那些潜在的问题,因为它知道的唯一参数是 bookssearch:

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)))()