阿里云主机折上折
  • 微信号
Current Site:Index > Array grouping method

Array grouping method

Author:Chuan Chen 阅读数:55413人阅读 分类: JavaScript

ECMAScript 15 Array Grouping Methods

ECMAScript 15 introduces new array grouping methods group and groupToMap, which allow grouping array elements based on specified conditions, returning an object or Map where the keys are the grouping criteria and the values are the corresponding arrays of elements.

Array.prototype.group

The group method takes a callback function as an argument. This callback function receives the current element, index, and the array itself, and returns a string as the grouping key. The method ultimately returns an object where the properties are the grouping keys and the values are the corresponding arrays of elements.

const inventory = [
  { name: 'asparagus', type: 'vegetables', quantity: 5 },
  { name: 'bananas',  type: 'fruit', quantity: 0 },
  { name: 'goat', type: 'meat', quantity: 23 },
  { name: 'cherries', type: 'fruit', quantity: 5 },
  { name: 'fish', type: 'meat', quantity: 22 }
];

const result = inventory.group(({ type }) => type);

console.log(result);
/*
{
  vegetables: [
    { name: 'asparagus', type: 'vegetables', quantity: 5 }
  ],
  fruit: [
    { name: "bananas", type: "fruit", quantity: 0 },
    { name: "cherries", type: "fruit", quantity: 5 }
  ],
  meat: [
    { name: "goat", type: "meat", quantity: 23 },
    { name: "fish", type: "meat", quantity: 22 }
  ]
}
*/

Array.prototype.groupToMap

The groupToMap method is similar to group but returns a Map object instead of a plain object. This is particularly useful when the grouping key is not a string, as Map keys can be any value.

const inventory = [
  { name: 'asparagus', type: 'vegetables', quantity: 5 },
  { name: 'bananas',  type: 'fruit', quantity: 0 },
  { name: 'goat', type: 'meat', quantity: 23 },
  { name: 'cherries', type: 'fruit', quantity: 5 },
  { name: 'fish', type: 'meat', quantity: 22 }
];

const result = inventory.groupToMap(({ quantity }) => 
  quantity < 5 ? 'restock' : 'adequate'
);

console.log(result);
/*
Map {
  'adequate' => [
    { name: 'asparagus', type: 'vegetables', quantity: 5 },
    { name: 'goat', type: 'meat', quantity: 23 },
    { name: 'cherries', type: 'fruit', quantity: 5 },
    { name: 'fish', type: 'meat', quantity: 22 }
  ],
  'restock' => [
    { name: 'bananas', type: 'fruit', quantity: 0 }
  ]
}
*/

Complex Grouping Example

The grouping methods can handle more complex grouping logic, such as grouping based on multiple conditions:

const people = [
  { name: 'Alice', age: 21, city: 'New York' },
  { name: 'Bob', age: 24, city: 'Chicago' },
  { name: 'Charlie', age: 21, city: 'New York' },
  { name: 'Dave', age: 24, city: 'Chicago' },
  { name: 'Eve', age: 30, city: 'Los Angeles' }
];

const grouped = people.group(({ age, city }) => `${age}-${city}`);

console.log(grouped);
/*
{
  '21-New York': [
    { name: 'Alice', age: 21, city: 'New York' },
    { name: 'Charlie', age: 21, city: 'New York' }
  ],
  '24-Chicago': [
    { name: 'Bob', age: 24, city: 'Chicago' },
    { name: 'Dave', age: 24, city: 'Chicago' }
  ],
  '30-Los Angeles': [
    { name: 'Eve', age: 30, city: 'Los Angeles' }
  ]
}
*/

Performance Considerations

For large arrays, the performance of grouping operations is important. The group and groupToMap methods are internally optimized and generally perform better than manually implemented equivalent code:

// Manual grouping implementation
function manualGroup(array, keyFn) {
  const result = {};
  for (const item of array) {
    const key = keyFn(item);
    if (!result[key]) {
      result[key] = [];
    }
    result[key].push(item);
  }
  return result;
}

// Using built-in methods
const largeArray = Array(1000000).fill().map((_, i) => ({ 
  id: i, 
  category: i % 10 
}));

console.time('built-in');
largeArray.group(x => x.category);
console.timeEnd('built-in');

console.time('manual');
manualGroup(largeArray, x => x.category);
console.timeEnd('manual');

Browser Compatibility

As of 2023, the group and groupToMap methods are implemented in the latest versions of major browsers, but older browsers may require a polyfill:

if (!Array.prototype.group) {
  Array.prototype.group = function(callback) {
    return this.reduce((acc, item, index, array) => {
      const key = callback(item, index, array);
      if (!acc[key]) {
        acc[key] = [];
      }
      acc[key].push(item);
      return acc;
    }, {});
  };
}

if (!Array.prototype.groupToMap) {
  Array.prototype.groupToMap = function(callback) {
    return this.reduce((acc, item, index, array) => {
      const key = callback(item, index, array);
      if (!acc.has(key)) {
        acc.set(key, []);
      }
      acc.get(key).push(item);
      return acc;
    }, new Map());
  };
}

Combining with Other Array Methods

Grouping methods can be chained with other array methods to create powerful data processing pipelines:

const products = [
  { id: 1, name: 'Laptop', category: 'Electronics', price: 999 },
  { id: 2, name: 'Smartphone', category: 'Electronics', price: 699 },
  { id: 3, name: 'Desk', category: 'Furniture', price: 299 },
  { id: 4, name: 'Chair', category: 'Furniture', price: 199 },
  { id: 5, name: 'Monitor', category: 'Electronics', price: 399 }
];

const result = products
  .filter(product => product.price > 200)
  .group(product => product.category);

console.log(result);
/*
{
  Electronics: [
    { id: 1, name: 'Laptop', category: 'Electronics', price: 999 },
    { id: 2, name: 'Smartphone', category: 'Electronics', price: 699 },
    { id: 5, name: 'Monitor', category: 'Electronics', price: 399 }
  ],
  Furniture: [
    { id: 3, name: 'Desk', category: 'Furniture', price: 299 }
  ]
}
*/

Practical Use Cases

Grouping methods are highly useful in data processing and presentation, especially when organizing data by categories:

// Data processing before visualization
const salesData = [
  { month: 'January', product: 'Widget A', sales: 100 },
  { month: 'January', product: 'Widget B', sales: 150 },
  { month: 'February', product: 'Widget A', sales: 200 },
  { month: 'February', product: 'Widget B', sales: 175 },
  { month: 'March', product: 'Widget A', sales: 120 },
  { month: 'March', product: 'Widget B', sales: 140 }
];

// Group by month
const byMonth = salesData.group(item => item.month);

// Group by product
const byProduct = salesData.group(item => item.product);

// Create chart data
const chartData = Object.entries(byMonth).map(([month, items]) => ({
  month,
  totalSales: items.reduce((sum, item) => sum + item.sales, 0)
}));

console.log(chartData);
/*
[
  { month: 'January', totalSales: 250 },
  { month: 'February', totalSales: 375 },
  { month: 'March', totalSales: 260 }
]
*/

Relationship with Object.groupBy and Map.groupBy

ECMAScript 15 also introduces static methods Object.groupBy and Map.groupBy, which function similarly to the instance methods but can be used with any iterable object:

const arrayLike = {
  length: 3,
  0: { name: 'Alice', age: 21 },
  1: { name: 'Bob', age: 24 },
  2: { name: 'Charlie', age: 21 }
};

const grouped = Object.groupBy(arrayLike, ({ age }) => age > 21 ? 'over21' : 'under22');

console.log(grouped);
/*
{
  under22: [
    { name: 'Alice', age: 21 },
    { name: 'Charlie', age: 21 }
  ],
  over21: [
    { name: 'Bob', age: 24 }
  ]
}
*/

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.