Сложная, но эффективная фильтрация массива JavaScript

1

Я получил очень большой массив объектов (лиц), структурированных таким образом

objects = [
  {
    firstname: 'Jo',
    lastname : 'Brown'
    mail: '[email protected]',
    courses: ['en', 'fr', 'es']

    ....and a lot more...
  },
  {
    firstname: 'Jack',
    lastname : 'Black'
    mail: '[email protected]',
    courses: ['en', 'fr']
    ....and a lot more...
  },
  {
    firstname: 'Jeff',
    lastname : 'Grey'
    mail: '[email protected]',
    courses: ['es']
    ....and a lot more...
  },

  ...and a lot more...
]

Первоначально я устанавливал другой массив, который должен содержать фильтрованных лиц только к основному массиву выше:

objectsFiltered = objects;

Мне нужно создать функцию для фильтрации этого массива с помощью

  1. строка, введенная пользователем в текстовое поле пользователем приложения (вход для поиска)
  2. некоторые другие критерии, выбираемые через ссылки или выпадающие меню...

Поэтому я сохраняю активированные фильтры в другом массиве следующим образом:

_objectsFilters = [
  {
    property: ['courses']
    value: ['es']
  },
  {
    property: ['firstname', 'lastname', 'mail']
    value: 'userStringInputGoesHere'
  }
]

В этом примере лица, чьи courses (Array) собственности courses (Array) содержат es и чье свойство firstname ИЛИ lastname ИЛИ mail содержат userStringInputGoesHere должны быть отфильтрованы.

Я использую функцию, чтобы получить/установить, сбросить фильтры следующим образом:

public set objectsFilters(objectsFilters: Array<ObjectsFilters>) {
  for (let filter of objectsFilters) {
    let index = this._objectsFilters.indexOf(filter);

    /* add filter if not already active */
    if(index === -1) {
      this._objectsFilters.push(filter);
      continue;
    }

    /* remove filter if active already */
    this._objectsFilters.splice(index, 1);
  }
}

public get objectsFilters(): Array<ObjectsFilters> {
  return this._nobjectsFilter;
}

Наконец, вопрос

Каков наилучший способ сброса фильтров и при этом отфильтрованные объекты (лица). Я подумал о двух способах управления этим:

Наберите "А

Использование другой функции для установки фильтрованных объектов (лиц) при каждом изменении objectsFilters. Поэтому функция всегда будет использовать нетронутый массив, содержащий ВСЕ лица (objects) и применять все фильтры. (Эффективность??!)

Тип B

Если применяется определенный фильтр, например, первый фильтр сверху:

{
  property: ['courses'],
  value: ['es']
},

сохраните теперь фильтрованных лиц в objectsFiltered ** и сохраните оставшихся лиц, которые неактивны из-за фильтра курсов, например:

objects = [
  {
    firstname: 'Jo',
    lastname : 'Brown'
    mail: '[email protected]',
    courses: ['en', 'fr', 'es']

    ....and a lot more...
  },
  {
    firstname: 'Jack',
    lastname : 'Black'
    mail: '[email protected]',
    courses: ['en', 'fr']
    ....and a lot more...
  },
  {
    firstname: 'Jeff',
    lastname : 'Grey'
    mail: '[email protected]',
    courses: ['es']
    ....and a lot more...
  },

  ...and a lot more...
]

_objectsFilters = [
  {
    property: ['courses']
    value: ['es']
  }
]

objectsFiltered = [
  {
    firstname: 'Jo',
    lastname : 'Brown'
    mail: '[email protected]',
    courses: ['en', 'fr', 'es']

    ....and a lot more...
  },
  {
    firstname: 'Jeff',
    lastname : 'Grey'
    mail: '[email protected]',
    courses: ['es']
    ....and a lot more...
  },

  ...and a lot more...
]

inactiveObjects = [
  {
    inactiveCause: {
      property: ['courses'],
      value: ['es']
    },
    /* containing all objects inactive because of the above filter */
    objects: [
      {
        firstname: 'Jack',
        lastname : 'Black'
        mail: '[email protected]',
        courses: ['en', 'fr']
        ....and a lot more...
      },
    ]
  }
]

Таким образом, сбросив определенный фильтр, я могу скопировать неактивных людей обратно на активных лиц.

Каким образом это правильный путь?

Теги:
arrays
filtering

1 ответ

0
Лучший ответ

Это похоже на классический случай преждевременной оптимизации.

В типе A вы всегда имеете одинаковые исходные данные и всегда запускаете один или несколько фильтров для этих данных. Первый фильтр будет единственным, работающим против полного набора данных; более поздние фильтры будут работать с постепенно меньшими наборами (потому что некоторые данные уже будут отфильтрованы).

В типе B вы изменяете исходные данные каждый раз, когда запускается фильтр, и блокируя отфильтрованные элементы в отдельном массиве. Как вы описали, это не сработает: если фильтр изменится, нет способа узнать, какие элементы необходимо восстановить в исходном массиве из stash (потому что вы не можете определить, какой фильтр удалил каждый объект). "Самый простой" подход к работе, о котором я могу думать, состоял бы в том, чтобы сохранить отдельный тайник для каждого фильтра, поэтому, когда фильтр X изменится, вы сбросите все объекты из отфильтрованного-на-X обратно в исходный код, а затем запустите фильтр X Это будет работать, но было бы довольно сложно поддерживать.

Сначала процитируйте простой метод A. Если у вас нет проблем с производительностью, все готово.

Если у вас есть проблемы с производительностью, не переходите прямо к методу B: вместо этого настройте порядок, в котором вы делаете фильтры: если данный фильтр может удалить больше данных, чем другие, сделайте это сначала. Если фильтр вычислительно дорогой, сделайте это последним.

Если у вас все еще есть проблемы с производительностью, вы можете попасть в героизм, задействованный в реализации метода B. (Это не произойдет. Если вы имеете дело с таким количеством клиентов с данными, что у вас есть проблемы с производительностью, которые его фильтруют, вы уже имеют гораздо большие проблемы с производительностью, просто загружая их в первую очередь...)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню