Фильтрация списка объектно-вложенных объектов с помощью объекта, содержащего пару ключ-массив - PullRequest
0 голосов
/ 10 ноября 2019

Я пытался придумать самый описательный заголовок.

Я придумал решение, но оно ужасно неэффективно, как порядка O (n ^ 4) или около того, что жалко.

Я пытаюсь отфильтровать и вернуть список объектов на основе объекта-фильтра и соответствующих значений ключа.

У меня будет список фильмов movieList, и я верну все фильмы, которые соответствуют всем парам ключ-значение, содержащимся в объекте movieFilter. В случае genre фильм должен быть одним из жанров. Так как продажи не включены в фильтр, мы не фильтруем его на основе этого.

let movieFilter = {
  "genre": ["Action", "Romance"],
  "director": "Bob",
  "writer": ["Jim", "Dave", "Alice"],
  "duration": "2"
}

let movie = {
  "genre" : "Action",
  "people": {
    "director": "Bob",
    "writer": "Alice"   
  }
  "boxoffice": "9,000,000",
  "duration": "2"
}

let movies = [{
  "genre" : "Action",
  "people": {
    "director": "Bob",
    "writer": "Alice"   
  }
  "boxoffice": "9,000,000",
  "duration": "2"
}, 
{
  "genre" : "Comedy",
  "people": {
    "director": "Rose",
    "writer": "Mike"   
  }
  "boxoffice": "12,000,000",
  "duration": "3"
}]

Проблема, с которой я столкнулся, заключается в том, что некоторые фильтры (например, фильтр genre) находятся в массивах, а некоторые ключи фильма(как people) вложены в объект, который я вынужден вкладывать в циклы, что увеличивает временную сложность.

Я мог бы изменить структуру фильтра, но то, как он сейчас работает, имеет смысл для меня. Формат объекта фильма - это то, что я не могу изменить.

Буду признателен за любые предложения о том, как мне справиться с этим.

Ответы [ 2 ]

2 голосов
/ 10 ноября 2019

Подумайте о замене ваших массивов объектами внутри вашего movieFilter.

let movieFilter = {
  genre: { Action: true, Romance: true },
  director: "Bob",
  writer: { Jim: true, Dave: true, Alice: true },
  duration: "2"
};

let movies = [
  {
    genre: "Action",
    people: {
      director: "Bob",
      writer: "Alice"
    },
    boxoffice: "9,000,000",
    duration: "2"
  },
  {
    genre: "Comedy",
    people: {
      director: "Rose",
      writer: "Mike"
    },
    boxoffice: "12,000,000",
    duration: "3"
  }
];

const filterOnMovieFilter = movie => {
  const { genre, people, duration } = movie;
  const { writer, director } = people || {};
  return (
    movieFilter.genre[genre] &&
    movieFilter.writer[writer] &&
    movieFilter.duration === duration &&
    movieFilter.director === director
  );
};
console.log(movies.filter(filterOnMovieFilter));

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

2 голосов
/ 10 ноября 2019

Это можно сделать, используя метод filter и метод some:

let movieFilter = {
  "genre": ["Action", "Romance"],
  "director": "Bob",
  "writer": ["Jim", "Dave", "Alice"],
  "duration": "2"
}

let movies = [
  {
  "genre": "Action",
  "people": {
    "director": "Bob",
    "writer": "Alice"
  },
  "boxoffice": "9,000,000",
  "duration": "2"
},
{
  "genre": "Comedy",
  "people": {
    "director": "Rose",
    "writer": "Mike"
  },
  "boxoffice": "12,000,000",
  "duration": "3"
}]

const result = movies.filter(f => movieFilter.genre.some(ge=> ge == f.genre)
                                  && movieFilter.director == f.people.director
                                  && movieFilter.writer.some(wr => wr == f.people.writer)
                                  && movieFilter.duration == f.duration
                            );
console.log(result);

ОБНОВЛЕНИЕ:

Благодаря комментарию @MkeSpaGuy. Я немного переработал подход к фильтрации ваших элементов.

Это слегка оптимизированная версия, использующая key для проверки выполнения условий фильтрации:

let movieFilter = {
  "genre": ["Action", "Romance"],
  "director": "Bob",
  "writer": ["Jim", "Dave", "Alice"],
  "duration": "2"
}

movieFilter.genre = movieFilter.genre.reduce((a, key) => ({...a, [key] : 1}), {});
movieFilter.writer = movieFilter.writer.reduce((a, key) => ({...a, [key] : 1}), {});

let movies = [{
  "genre" : "Action",
  "people": {
"director": "Bob",
"writer": "Alice"
  },
  "boxoffice": "9,000,000",
  "duration": "2"
},
{
  "genre" : "Comedy",
  "people": {
"director": "Rose",
"writer": "Mike"
  },
  "boxoffice": "12,000,000",
  "duration": "3"
}];


const result = movies.filter(f => movieFilter.genre[f.genre]
                              && movieFilter.director == f.people.director
                              && movieFilter.writer[f.people.writer]
                              && movieFilter.duration == f.duration
);
console.log(result);
...