Skip to content

Instantly share code, notes, and snippets.

@bryandh
Last active September 30, 2021 13:32
Show Gist options
  • Save bryandh/c0cd25df7ccfdf891bf782174535f4ca to your computer and use it in GitHub Desktop.
Save bryandh/c0cd25df7ccfdf891bf782174535f4ca to your computer and use it in GitHub Desktop.
Typescript Array utilities
export class ArrayUtilities {
/**
* Groups a collection by a property to a Map type.
* @param collection The collection to group.
* @param groupKeyResolver Contains the property to group by, computed from a function.
* @returns Map key-value pair collection with given property as key and elements with that property as values.
*/
public static groupBy<K, T>(collection: T[], groupKeyResolver: (item: T) => K): Map<K, T[]> {
return collection.reduce(
(map: Map<K, T[]>, item: T) => {
// Get the group name from the groupKeyResolver function, this will be the key of the group in the array.
const key = groupKeyResolver(item);
// Add the object to the group at the computed key.
return map.set(
key,
map.get(key) // Retrieve any previous values at the key.
? map.get(key).concat(item) // Concat the object to the already existing values.
: [item] // Set the values as a new array with just the object.
);
},
new Map<K, T[]>() // Create a new Map collection which will serve as the initial prev value.
);
}
/**
* Groups a collection by a property to a multidimensional array
* @param collection The collection to group
* @param groupKeyResolver Contains the property to group by, computed from a function.
* @returns T[][] Multidimensional array key-value pair collection with given property as key and elements with that property as values.
*/
public static group<T>(collection: T[], groupKeyResolver: (item: T) => any): T[][] {
return collection.reduce(
(prev: T, next: T) => {
// Get the group name from the property function, this will be the index of the group in the array
const groupName = groupKeyResolver(next);
// Set the group in the array to either its previous value (prev[groupName])
// if that exists, otherwise fill it with an empty array
prev[groupName] = prev[groupName] || [];
// Add the next item to the group's array
prev[groupName].push(next);
return prev;
},
Object.create(null)
);
}
/**
* Sums a collection by a property
* @param collection The collection to sum
* @param property The property to sum, represented in a function
*/
public static sum<T>(collection: T[], property: (item: T) => number): number {
return collection.reduce((prev: 0, next: T) => {
return prev + (isNaN(Number(property(next))) ? 0 : Number(property(next)));
}, 0);
}
/**
* Segment an array to an array of arrays based on a key within the items
*/
public static segmentBy<T>(collection: T[], seperatorFunc: (item: T) => any): T[][] {
const segments = [];
let currentSegment: T[] = [];
let lastSeperator = null;
for (const item of collection) {
const currentSeperator = seperatorFunc(item);
// Set the initial separator
if (!lastSeperator)
lastSeperator = currentSeperator;
if (currentSeperator === lastSeperator)
// Add the item to the segment as it has the same separator as the last
currentSegment.push(item);
else {
// Add the current segment to the segments array as we're not adding any more items to it
segments.push(currentSegment);
// Start a new current segment with the current item
currentSegment = [item];
lastSeperator = currentSeperator;
}
}
// add the last one
segments.push(currentSegment);
return segments;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment