Алгоритмическое решение задачи без использования цикла for

Я пытаюсь решить следующий случай без использования цикла for... Это означает, что я пытаюсь использовать только фильтр, уменьшение, карту или их комбинацию.

Я получил массив объектов:

const items = 
  [ { label: 1, count: 22, isRefined: false } 
  , { label: 2, count: 10, isRefined: false } 
  , { label: 3, count:  3, isRefined: false } 
  , { label: 4, count:  1, isRefined: false } 
  ]
 
const products = 
  [ { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 }                       ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 } , { LocationType: 4 } ]} 
  , { Locations: [{ LocationType: 1 }                                             ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  ]

Дело следующее:

Мне нужно перезаписать внутренний ключ счетчика объектов каждого элемента значением соответствующих продуктов с объектами, в которых объекты Locations содержат соответствующий тип Location для метки объекта items...

Например, вывод здесь должен быть

const output = 
  [ { label: 1, count: 5, isRefined: false } 
  , { label: 2, count: 2, isRefined: false } 
  , { label: 3, count: 4, isRefined: false } 
  , { label: 4, count: 1, isRefined: false } 
  ] 

Я полностью застрял в попытке найти решение без использования цикла for или любого другого цикла for, помощь будет очень признательна! Спасибо

Под циклом for вы имеете в виду конкретно for (let i = 0; i < someNum; i++) или вы имеете в виду любую форму итерации? Как насчет .map() или .forEach() в массиве?

Sal 25.12.2020 00:41

Разве label: 3 не должно быть count из 4 вместо 3? Пожалуйста, проверьте свои примеры заранее

ibrahim mahrir 25.12.2020 00:41

«Массив (#)» недействителен. Как рекомендовал Ибрагим, нам нужны действительные ориентиры, прежде чем мы сможем реально помочь.

Randy Casburn 25.12.2020 00:43

Ваш инструктор, скорее всего, пытается указать вам на использование reduce или map.

Randy Casburn 25.12.2020 00:45

Извините, я исправил ошибки. Под циклом for я подразумеваю конкретно for (let i = 0; i < someNum; i++)```, forEach, forOf. Да, он сказал, что предпочтительнее использовать сокращение, карту или фильтр.

Mister Smth 25.12.2020 00:46

Пожалуйста, проверьте мой ответ, не используются for/forEach/forOf, только map и filter.

Reqven 25.12.2020 01:16
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
6
139
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Сначала подсчитайте количество (количество раз, когда каждый тип местоположения появляется в массиве products), желательно в виде объекта, где ключи — это типы местоположения, а значения — количество. Для этого простой reduce/forEach выполнит эту работу следующим образом:

let counts = products.reduce((counts, locs) => {
  locs.Locations.forEach(loc =>
    counts[loc.LocationType] = (counts[loc.LocationType] || 0) + 1
  );
  return counts;
}, {});

Затем просто map массив items в новый массив, где вы неглубоко копируете объекты, используя синтаксис распространения, и обновляете свойство count, используя объект counts, рассчитанный ранее:

const newItems = items.map(item => ({
  ...item,
  count: counts[item.label] || 0
}));

А если вы хотите вместо этого изменить сами исходные объекты, то простого forEach будет достаточно:

items.forEach(item => item.count = counts[item.label] || 0);

Часть || 0 является резервным значением на случай, если элемент не имеет типов местоположения в массиве products, и в этом случае counts[item.label] будет undefined, а вместо него будет использоваться 0. Это называется оценкой короткого замыкания.

Демо:

const items = [{label: 1, count: 22, isRefined: false}, {label: 2, count: 10, isRefined: false}, {label: 3, count: 3, isRefined: false},{label: 4, count: 1, isRefined: false}];

const products = [{Locations:[{LocationType:1},{LocationType:2},{LocationType:3}]},{Locations:[{LocationType:1},{LocationType:3}]},{Locations:[{LocationType:1},{LocationType:3},{LocationType:4}]},{Locations:[{LocationType:1}]},{Locations:[{LocationType:1},{LocationType:2},{LocationType:3}]}];



let counts = products.reduce((counts, locs) => {
  locs.Locations.forEach(loc =>
    counts[loc.LocationType] = (counts[loc.LocationType] || 0) + 1
  );
  return counts;
}, {});

const newItems = items.map(item => ({
  ...item,
  count: counts[item.label] || 0
}));

console.info(newItems);

Большое спасибо! Работает как шарм, я проверю у него, приемлем ли forEach. :)

Mister Smth 25.12.2020 01:08

@BranislavBrnjoš Добро пожаловать! Я рад, что смог помочь :)

ibrahim mahrir 25.12.2020 01:09
Ответ принят как подходящий

Простой и элегантный.

ОБНОВЛЕНИЕ
Спасибо @plichard за предложение в комментариях ниже использовать метод some() и деструктуризацию объекта в обратном вызове filter. Это действительно аккуратно!

const output = items.map(item => {
  const matches = (location) => location.LocationType == item.label;
  const filtered = products.filter(({ Locations }) => Locations.some(matches));
  return { ...item, count: filtered.length };
});
some() кажется более подходящим, чем принуждение логического значения из фильтра. products.filter(({ Locations }) => Locations.some(matches));
pilchard 25.12.2020 01:17

@pilchard Не думал об этом, так даже лучше, спасибо!

Reqven 25.12.2020 01:24

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

const result = items.map(d => {
    const locationCount = products.reduce((count, p) => count + p.Locations.filter(l => l.LocationType == d.label).length, 0);
    let item = Object.assign({}, d);
    item.count = locationCount;
    return item;
 })

Например:

const items = 
  [ { label: 1, count: 22, isRefined: false } 
  , { label: 2, count: 10, isRefined: false } 
  , { label: 3, count:  3, isRefined: false } 
  , { label: 4, count:  1, isRefined: false } 
  ] 
const products = 
  [ { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 }                       ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 } , { LocationType: 4 } ]} 
  , { Locations: [{ LocationType: 1 }                                             ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  ] 

const result = items.map(d => {
    const locationCount = products.reduce((count, p) => count + p.Locations.filter(l => l.LocationType == d.label).length, 0);
    let item = Object.assign({}, d);
    item.count = locationCount;
    return item;
})

console.info(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Ваше решение нарушает целостность items (их значения счетчика изменены)

Mister Jojo 25.12.2020 02:15

@MisterJojo исправлено, спасибо за указание

Sharon Choong 25.12.2020 02:48

одна строчка: return Object.assign({}, d, {count: locationCount})

Mister Jojo 25.12.2020 03:09

мой путь...

const countP = v => products.filter(p=>p.Locations.some(x=>x.LocationType===v)).length

const output = items.map(el=>({...el, count: countP(el.label)}))

доказательство:

const items = 
  [ { label: 1, count: 22, isRefined: false } 
  , { label: 2, count: 10, isRefined: false } 
  , { label: 3, count:  3, isRefined: false } 
  , { label: 4, count:  1, isRefined: false } 
  ] 

const products = 
  [ { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 }                       ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 3 } , { LocationType: 4 } ]} 
  , { Locations: [{ LocationType: 1 }                                             ]} 
  , { Locations: [{ LocationType: 1 } , { LocationType: 2 } , { LocationType: 3 } ]} 
  ] 

const countP = v => products.filter(p=>p.Locations.some(x=>x.LocationType===v)).length

const output = items.map(el=>({...el, count: countP(el.label)}))  
console.info( output )
.as-console-wrapper { max-height: 100% !important; top: 0; }
.as-console-row         { background-color: #87f1f1; }
.as-console-row::after  { display:none !important; }

Другие вопросы по теме