Фильтровать массив объектов с несколькими критериями и частичными совпадениями - PullRequest
0 голосов
/ 05 декабря 2018

Я нашел много фильтров для массивов объектов с несколькими критериями, но они, кажется, точно совпадают.Мне нужен способ фильтрации частичных совпадений.Кажется, я нахожу либо одну, либо другую.

let products = [
  { name: "A", color: "Blue", size: 50 },
  { name: "B", color: "Blue", size: 60 },
  { name: "C", color: "Black", size: 70 },
  { name: "D", color: "Green", size: 50 },
];

let filters = {
  color: "Blue",
  size: "70"
};

function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters);
  return array.filter((item) => {
  return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
  });

var filtered = multiFilter(products, filters);

(https://gist.github.com/jherax/f11d669ba286f21b7a2dcff69621eb72)

Я использую эту функцию - и она прекрасно работает! Но совпадения должны быть точными. Как сделатьЯ изменил это на частичное совпадение? А также прописные или строчные буквы? Я пробовал много способов, но, похоже, он не работает правильно. Любая помощь будет оценена!

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

По сути, вы ищете Regular Expression.вам нужно изменить

filterKeys.every(key => !!filters[key].indexOf(item[key]))

на

!filterKeys.some(key => RegExp(filters[key], 'i').test(item[key].toString()));

конечно, позаботьтесь, используя item[key].toString(), потому что в зависимости от случаяможет привести к проблеме, в этом случае я использовал ее из-за цифр (размер ключа продуктов).

let products = [{
    name: "A",
    color: "Blue",
    size: 50
  },
  {
    name: "B",
    color: "Blue",
    size: 60
  },
  {
    name: "C",
    color: "Black",
    size: 70
  },
  {
    name: "D",
    color: "Green",
    size: 50
  },
  {
    name: "D",
    color: "bluePartial", //you are looking for blue, but blue is a substring of bluepartial, this will be filtered as well
    size: 50
  },
  {
    name: "D",
    color: "violet",
    size: 700 // same as above, 70 is a substring of 700
  },
];

// the value of each key is an array with the values to filter
let filters = {
  color: "Blue",
  size: "70"
};

function multiFilter(array, filters) {
  const filterKeys = Object.keys(filters);
  return array.filter((item) => {
    return !filterKeys.some(key => RegExp(filters[key], 'i').test(item[key].toString()));
  });
}

var filtered = multiFilter(products, filters);
console.log(filtered)
0 голосов
/ 06 декабря 2018

Вы можете попробовать что-то вроде этого:

let rows = [ { name: "A", color: "Blue", size: "50" }, { name: "B", color: "Blue", size: "60" }, { name: "C", color: "Black", size: "70" }, { name: "D", color: "Green", size: "50" }, ];

const filter = (a, f) => {
  let keys = Object.keys(f)
  if(keys.length == 1) {
    return a.filter(x => x[keys[0]].toLowerCase().includes(f[keys[0]].toLowerCase()))
  } else return a.filter(x => Object.values(f).every(fv => {
    return Object.values(x).some(v => v.toLowerCase().includes(fv.toLowerCase()))
  }))
}

console.log(filter(rows, {color: "Blu", size: "50"}))
console.log(filter(rows, {color: "G", size: "5"}))
console.log(filter(rows, {name: "b"}))
console.log(filter(rows, {size: "6"}))

Идея состоит в том, что если у вас есть только 1 фильтр к filter по значению поля (в противном случае b будет соответствовать как name: "B", так и color: "Blue" ивместо 1 результата вы получите 3), но если у вас есть более одного, чтобы отфильтровать все значения из объекта filter.

Код использует String.includes для обработки частичных совпадений и String.toLowerCase для значений для сравнения.

0 голосов
/ 05 декабря 2018

Чтобы преобразовать существующий код, вам нужно переключиться вокруг фильтра, как указано @Vasan.

Это означает, что значения свойств в products будут проверены, чтобы увидеть, являются ли значениясовпадающими свойствами filters являются подстроки.Однако некоторые поля в products не являются строками.Поэтому мы сначала преобразуем их все в строки, хотя я не уверен, насколько полезно искать «size: 1» и получать элементы «size: 100».

    let products = [
      { name: "A", color: "Blue", size: 50 },
      { name: "B", color: "Blue", size: 60 },
      { name: "C", color: "Black", size: 70 },
      { name: "D", color: "Green", size: 50 }
    ];
    
    let filters = {
      color: "Blu",
      size: "50"
    };

    function multiFilter(array, filters) {
      const filterKeys = Object.keys(filters);
      return array.filter((item) => {
        // flipped around, and item[key] forced to a string
        return filterKeys.every(key => !!~String(item[key]).indexOf(filters[key]));
      });
    }

    var filtered = multiFilter(products, filters);
    console.log(filtered);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...