Функциональное Javascript отображение / уменьшение при подготовке данных отчета - PullRequest
1 голос
/ 29 марта 2020

Я пытаюсь понять, как правильно использовать Array.reduce () для сбора сводных данных / данных отчета (т. Е. Сгруппированных подсчетов). Обычно я делаю это вручную, зацикливая данные с помощью forEach и создавая объект, но я чувствую, что цепочка карт и уменьшение - это более элегантный, функциональный способ сделать это; Я просто не могу понять, как сделать это правильно.

Вот где меня поэкспериментировали:

const articleData = [
    {newsSource: "AP", title: "Some article.", category: "World"},
    {newsSource: "BBC", title: "Some article.", category: "Politics"},
    {newsSource: "CBS", title: "Some article.", category: "Sports"},
    {newsSource: "CNN", title: "Some article.", category: "Finance"},
    {newsSource: "CNN", title: "Another article.", category: "Politics"},
    {newsSource: "NBC", title: "Some article.", category: "Politics"},
    {newsSource: "NBC", title: "Another article.", category: "Finance"},
    {newsSource: "Reuters", title: "Some article.", category: "World"},
    {newsSource: "Reuters", title: "Another article.", category: "Politics"},
    {newsSource: "Reuters", title: "Yet another article.", category: "Finance"}
];

// I want to set reportData to be the result of the chained map/reduce
// ...not declare it here and assemble it within the functions below
let reportData = {};

articleData.map((item, index) => {
    if (item.newsSource) return item.newsSource;
})
.reduce((acc, newsSource) => {

    if (!reportData[newsSource]) {
        reportData[newsSource] = 1;
    } else {
        reportData[newsSource] = reportData[newsSource] + 1;
    }

    return (acc, reportData);

});

console.log(reportData);
// Expected output:
// { AP: 1, BBC: 1, CBS: 1, CNN: 2, NBC: 2, Reuters: 3 }

Здесь есть ряд проблем. (Не в последнюю очередь это то, что он пропускает первый элемент данных! Я думаю Я понимаю, почему, но я не знаю, как это исправить.) Но самое главное, я хочу понять, как построить моя reduce функция, поэтому я не изменяю reportData внутри нее, скорее я возвращаю правильно структурированные данные, показанные в разделе «Ожидаемый результат».

Уменьшение плоского массива мне ясно, но я запутаться, как только я столкнусь со структурой любой глубины.

Ответы [ 2 ]

2 голосов
/ 29 марта 2020

Вы можете просто использовать Array.reduce непосредственно на articleData:

reportData = articleData.reduce(function(c, a) {
  c[a.newsSource] = (c[a.newsSource] || 0) + 1;
  return c;
}, {});

console.log(reportData);

Обратите внимание, что, как указано @CertainPerformance в их комментарии, вам нужно передать начальное значение в reduce в противном случае первое значение в массиве используется в качестве начального значения и не включается в итерацию.

const articleData = [{
    newsSource: "AP",
    title: "Some article.",
    category: "World"
  },
  {
    newsSource: "BBC",
    title: "Some article.",
    category: "Politics"
  },
  {
    newsSource: "CBS",
    title: "Some article.",
    category: "Sports"
  },
  {
    newsSource: "CNN",
    title: "Some article.",
    category: "Finance"
  },
  {
    newsSource: "CNN",
    title: "Another article.",
    category: "Politics"
  },
  {
    newsSource: "NBC",
    title: "Some article.",
    category: "Politics"
  },
  {
    newsSource: "NBC",
    title: "Another article.",
    category: "Finance"
  },
  {
    newsSource: "Reuters",
    title: "Some article.",
    category: "World"
  },
  {
    newsSource: "Reuters",
    title: "Another article.",
    category: "Politics"
  },
  {
    newsSource: "Reuters",
    title: "Yet another article.",
    category: "Finance"
  }
];

reportData = articleData.reduce(function(c, a) {
  c[a.newsSource] = (c[a.newsSource] || 0) + 1;
  return c;
}, {});

console.log(reportData);
1 голос
/ 29 марта 2020

Вы можете передать значение кулака для накопления в методе 2nd param из reduce. Вы можете пропустить значение или manipulate значение в функции callback.

const articleData = [
  { newsSource: "AP", title: "Some article.", category: "World" },
  { newsSource: "BBC", title: "Some article.", category: "Politics" },
  { newsSource: "CBS", title: "Some article.", category: "Sports" },
  { newsSource: "CNN", title: "Some article.", category: "Finance" },
  { newsSource: "CNN", title: "Another article.", category: "Politics" },
  { newsSource: "NBC", title: "Some article.", category: "Politics" },
  { newsSource: "NBC", title: "Another article.", category: "Finance" },
  { newsSource: "Reuters", title: "Some article.", category: "World" },
  { newsSource: "Reuters", title: "Another article.", category: "Politics" },
  { newsSource: "Reuters", title: "Yet another article.", category: "Finance" }
];

const reportData = articleData.reduce((acc, { newsSource }) => {
  if (!acc[newsSource]) acc[newsSource] = 0;
  acc[newsSource] += 1;
  return acc;
}, {});

console.log(reportData);
...