Объединение методов массива (фильтр, отображение, уменьшение) вместо использования двойного цикла - PullRequest
1 голос
/ 05 августа 2020

Я столкнулся с проблемой, которую просто не могу понять ... вот что я пытаюсь сделать.

Учитывая следующий массив объектов,

products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

Я знаю, что могу запустить это через вложенный l oop, чтобы добавить ключи по имени ингредиента, а затем увеличить значение как I l oop с помощью счетчика, как показано ниже:

      let ingredientCount = {}; 

  for (i = 0; i < products.length; i += 1) {
    for (j = 0; j < products[i].ingredients.length; j += 1) { //loop ingredients 
      ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1; 
    }
  }

В результате , componentCount должно быть примерно таким: {"артишок": 1 "грибы": 2} ***

Проблема в том, что мне нужно использовать карту и уменьшить, чтобы получить те же результаты, что и выше. .

let ingredientCount = {}

    ingredientCount = 
    products.filter ((value) => {
        // filter out arrays within ingredients 
        // so out come should be like  
        /* 
        [ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms']
        ,ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary']
        ,ingredients: ['black beans', 'jalapenos', 'mushrooms']
        ,ingredients: ['blue cheese', 'garlic', 'walnuts']
        ,ingredients: ['spinach', 'kalamata olives', 'sesame seeds']
        */

    }).map ((value) => {
        /* then take out ingredients and map this array to  
        arthichoke: ['artichoke','artichoke','artichoke']
        sundried tomatoes: ['sundried tomatoes']
        etc... 
        */

    
    }).reduce((acc, value) => {
        /* then reduce arrays within each key to numbers. 
        hence, the output should be 

        artichokes: artichokes.length (i.e. 3 )
        sundried toamatoes: 1
        
        */
    })

Могу ли я использовать вышеуказанные методы массива для того же результата без необходимости использовать l oop?

Заранее спасибо.

Ответы [ 5 ]

0 голосов
/ 05 августа 2020

Используйте flatMap и reduce. (В дополнение к операторам ?? и ,)

const products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

const ingredientCount = products
  .flatMap(({ ingredients }) => ingredients)
  .reduce((acc, item) => ((acc[item] = (acc[item] ?? 0) + 1), acc), {});

console.log(ingredientCount);
0 голосов
/ 05 августа 2020

Используйте Array.prototype.reduce, чтобы уменьшить массив и увеличить счетчик, как вы go.

const products = [{
    name: 'Sonoma',
    ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'],
    containsNuts: false
  },
  {
    name: 'Pizza Primavera',
    ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'],
    containsNuts: false
  },
  {
    name: 'South Of The Border',
    ingredients: ['black beans', 'jalapenos', 'mushrooms'],
    containsNuts: false
  },
  {
    name: 'Blue Moon',
    ingredients: ['blue cheese', 'garlic', 'walnuts'],
    containsNuts: true
  },
  {
    name: 'Taste Of Athens',
    ingredients: ['spinach', 'kalamata olives', 'sesame seeds'],
    containsNuts: true
  },
];

const result = products.reduce((acc, { ingredients }) => {
  ingredients.forEach((ingredient) => {
    acc[ingredient] = (acc[ingredient] || 0) + 1;
  });
  return acc;
}, Object.create(null));

console.log(result);
0 голосов
/ 05 августа 2020

Вы можете использовать два forEach или map и поддерживать последний массив, который нужно только обновить.

let products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

let iCount = {};
products.forEach((c) => c.ingredients.forEach((i) => iCount.hasOwnProperty(i) ? iCount[i]++ : iCount[i] = 1));
console.log(iCount);
0 голосов
/ 05 августа 2020

Решение, использующее метод .reduce и метод .forEach массива.

var products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

var result = products.reduce((acc,obj) => 
   {obj.ingredients.forEach(ob=> acc[ob] = acc[ob]+1 || 1)
    return acc;
},{});

console.log(result);
0 голосов
/ 05 августа 2020

Вам нужно использовать map(), flat(), а затем reduce(). Функция flat() выравнивает массив.

products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

let obj = products
              .map(p => p.ingredients)
              .flat()
              .reduce((obj, val) => {
                  obj[val] = (obj[val] || 0) + 1;
                  return obj;
              }, {});
console.log(obj);
...