Использование карты с редуктором в JavaScript для фильтрации объектов в массиве - PullRequest
0 голосов
/ 23 сентября 2018

Есть вопрос от freecodecamp, а детали следующие:

Требование:
Создайте функцию, которая просматривает массив объектов (первый аргумент) и возвращает массив всех объектов, которые соответствуютпары имя и значение (второй аргумент).

Например, если первый аргумент - [{first: "Romeo", last: "Montague"}, {first: "Mercutio", last: null},{first: "Tybalt", last: "Capulet"}], а вторым аргументом является {last: "Capulet"}, затем вы должны вернуть третий объект из массива (первый аргумент), поскольку он содержит имя иего значение, которое было передано в качестве второго аргумента.

Ожидаемый результат:

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }) should return [{ "apple": 1, "bat": 2, "cookie": 2 }].

whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }) should return [{ "apple": 1, "bat": 2 }, { "apple": 1, "bat": 2, "cookie":2 }].

И, согласно сайту, существует решение, подобное этому:

function whatIsInAName(collection, source) {
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function (obj) {
    return srcKeys
      .map(function(key) {
        return obj.hasOwnProperty(key) && obj[key] === source[key];
      })
      .reduce(function(a, b) {
        return a && b;
      });
  });
}

// test here
whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });

В этом решении есть одна вещь, которую я не совсем понимаю, это возвращаемое значение из функции карты.

Прежде, чем я ожидал, функция map будет перебирать все пары ключей и значений, чтобы проверить, совпадает ли она или нет, и возвращать массив с логическим значением, т.е. sth like [{true, false}, {false, false}] и т. д., и передайте логическое значение в функцию Reduce.

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

var source = { last: "Capulet" };
var collection = [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }];
var srcKeys = Object.keys({ last: "Capulet" });

collection.filter(function(obj){
  return srcKeys.map(function(key){
    return obj.hasOwnProperty(key) && obj[key] === source[key];
  })
})

И результат будет таким:

(3) [{…}, {…}, {…}]
 0: {first: "Romeo", last: "Montague"}
 1: {first: "Mercutio", last: null}
 2: {first: "Tybalt", last: "Capulet"}
 length: 3
  __proto__: Array(0)

В этом случае у меня есть 2Вопросы:

  1. В функции карты она создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.В этом случае, поскольку мы хотим вернуть только элементы, которые соответствуют условиям, почему он не возвращает логическое значение или только элементы с совпадающим значением, но возвращает все значения?Или у меня есть что-то, что я неправильно понял в функции отображения?

  2. В функции сокращения, которая после функции отображения, Как она может получить сопоставленные логические значения для одного логического значения, которое указываетвсе ли srcKeys проходят условия, проверенные выше?Например, в этом случае, функция приведения просто принимает возвращаемое значение карты и вычисляет дальше?

Большое спасибо за помощь заранее!

Ответы [ 2 ]

0 голосов
/ 23 сентября 2018

Часть map отображает все пары ключ-значение source в массив логических значений, указывающих, находится ли значение в объекте:

 var obj = { a: 1, c: 3 };
 var source = { a: 1, b: 2, c: 3 };

 var mapped = Object.keys(source).map(key => obj[key] === source[key]);

 console.log(mapped); // [true, false, true]

Теперь этот массив нельзя использоватькак возвращаемое значение для фильтрации напрямую, потому что массивы всегда верны, независимо от того, что их insode.Теперь редуктор превращает этот массив в одно логическое значение, следующее:

 [true, false, true].reduce((a, b) => a && b) // false

То же, что и:

 true && false && true // false

Таким образом, в конце он возвращает true, если все значения ключа существуют.


PS: остановите этот курс, предлагаемый код ужасен.

0 голосов
/ 23 сентября 2018

Как я уже сказал, функция map не нужна.

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

let whatIsInAName = (arr, obj) => arr.filter(o => Object.keys(obj).every(k => obj[k] === o[k]));

console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }));
console.log(whatIsInAName([{ "first": "Romeo", "last": "Montague" }, { "first": "Mercutio", "last": null }, { "first": "Tybalt", "last": "Capulet" }], { "last": "Capulet" }));
console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }));
console.log(whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 }));
.as-console-wrapper { max-height: 100% !important; top: 0; }
...