javascript - 2d array - group by first item and calculate average of corresponding number - Stack Overflow

admin2025-04-25  2

I have a 2d array which contains a list of series with title, rating, and time spent watching. For example:

let seriesList = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]];

A series can appear multiple times with a different rating. I would like to calculate the average rating for each series (and get another 2d array with each series appearing only once).

So far, I used reduce() on the array in order to do the sum of all the ratings, but I can't figure out how to get the number of ratings so I can divide by it.

let seriesList = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]; // example of values in my array, but it's actually much longer and it will change with each new series i watch
    
let seriesListAverage = Object.values(
    seriesList.reduce((accumulator, currentValue) => {

      if (accumulator[currentValue[0]]) {
        accumulator[currentValue[0]][1] += currentValue[1]; // do the sum of all ratings
      }
      else {
        accumulator[currentValue[0]] = currentValue;
      }
      return accumulator;
    }, {})
);

console.log(seriesListAverage); // Result: [["Squid Game", 6, "4 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]

// Expected result: [["Squid Game", 3, "4 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]

I have a 2d array which contains a list of series with title, rating, and time spent watching. For example:

let seriesList = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]];

A series can appear multiple times with a different rating. I would like to calculate the average rating for each series (and get another 2d array with each series appearing only once).

So far, I used reduce() on the array in order to do the sum of all the ratings, but I can't figure out how to get the number of ratings so I can divide by it.

let seriesList = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]; // example of values in my array, but it's actually much longer and it will change with each new series i watch
    
let seriesListAverage = Object.values(
    seriesList.reduce((accumulator, currentValue) => {

      if (accumulator[currentValue[0]]) {
        accumulator[currentValue[0]][1] += currentValue[1]; // do the sum of all ratings
      }
      else {
        accumulator[currentValue[0]] = currentValue;
      }
      return accumulator;
    }, {})
);

console.log(seriesListAverage); // Result: [["Squid Game", 6, "4 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]

// Expected result: [["Squid Game", 3, "4 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]]

(If it matters, the script is written in Apps Script, I get the values for seriesList from a sheet of my Sheets file, and I print the result into another sheet. That's why I need a 2d array.)

Share Improve this question edited Jan 15 at 19:55 Jats PPG 8631 gold badge1 silver badge12 bronze badges asked Jan 15 at 18:19 amyamy 839 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 1
function listAvg() {
  const arr = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]];
  let obj = arr.reduce((a,r,i) => {
    let p = r[0];
    if(!a.hasOwnProperty(p)) {
      a[p] = {row:r,count:1};
      a.pA.push(p);
    } else {
      a[p]["row"][1] += r[1];
      a[p]["count"] += 1;
    }
    return a;
  },{pA:[]});
  obj.pA.forEach(p => {
    obj[p]["row"][1] = obj[p]["row"][1]/obj[p]["count"];
    obj[p]["row"].splice(2,1);//remove last element
    Logger.log(JSON.stringify(obj[p].row));
  })
  const end = "is near"
}

Execution log
1:01:03 PM  Notice  Execution started
1:00:58 PM  Info    ["Squid Game",3] //Name,Average
1:00:58 PM  Info    ["Buffy the Vampire Slayer",5]
1:00:58 PM  Info    ["The Fosters",3]
1:01:05 PM  Notice  Execution completed

You could group first and then get the average.

const
    series = [["Squid Game", 3.5, "4 days"], ["Squid Game", 2.5, "3 days"], ["Buffy the Vampire Slayer", 5, "32 days"], ["The Fosters", 3, "5 days"]],
    result = Object
        .values(Object.groupBy(series, ([serie]) => serie))
        .map(group => [group[0][0], group.reduce((t, [_, r]) => t + r, 0) / group.length]);

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

转载请注明原文地址:http://anycun.com/QandA/1745563136a90924.html