Skip to content

Instantly share code, notes, and snippets.

@ccurtin
Last active March 4, 2019 03:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ccurtin/2ab4f30e4062928d6797ce98da945e3c to your computer and use it in GitHub Desktop.
Save ccurtin/2ab4f30e4062928d6797ce98da945e3c to your computer and use it in GitHub Desktop.
Creates index keys based on key matches for an array of objects
/**
* Creates index keys. Groups an array of objects by the specified key group.
* Note: if there are multiple objects with the same key and the type arg is set to `object`, only the frst match will be included in the result
* @exmaple:
* const users = [{name:"jill", favColor:"teal"}, {name:"kim", favColor:"blue"},{name:"rachel", favColor:"teal"}]
* groupArrayItemsByKey(users, 'favColor')
* output:
* {
* teal":[
* {"name":"jill","favColor":"teal"},
* {"name":"rachel","favColor":"teal"}
* ],
* "blue":{"name":"kim","favColor":"blue"} // NOTICE: if `type` was set to `array`, the `blue` key would be a 0-indexed array instead of an object
* }
* @param {array} items An array of objects
* @param {string} key The key to group by
* @param {string} type Enables user to force key match content as an array|object. type="object" will always ONLY include a single match in the result(ignoring any additional key matches in the items array).
* @return {object} The items grouped by the key
*/
const groupArrayItemsByKey = (items, key, type) => {
const itemKeys = items.map(x => x[key])
return items.reduce((acc, current) => {
hasMultiple = type !== 'object' ? itemKeys.indexOf(current[key]) < itemKeys.lastIndexOf(current[key]) : false
asArray = hasMultiple ? ( acc[current[key]] || [] ).concat(current) : (type == 'array' ? [current] : (current || {}))
asObject = current || {}
// will store as Array(if multiple `current[key]` keys are found in `items`) or stores it as Object if only one instance of `current[key]` is found in `items`
mixed = hasMultiple ? asArray : asObject,
data = !type ? mixed : (type === 'object' ? asObject : asArray)
return Object.assign(acc, { [current[key]]: data })}, {})
}
// Minified Version:
// groupArrayItemsByKey=((a,e,t)=>{r=a.map(a=>a[e]);return a.reduce((a,s)=>(h="object"!==t&&r.indexOf(s[e])<r.lastIndexOf(s[e]),l=h?(a[s[e]]||[]).concat(s):"array"==t?[s]:s||{},o=s||{},mixed=h?l:o,data=t?"object"===t?o:l:mixed,Object.assign(a,{[s[e]]:data})),{})});
/**
* Takes a shallow array of objects and will return an Object with unique "keys" based on the key
* @param {array} items
* @param {string} keys The key to sort by
* @return {object} New object with unique key values based on the "key" argument. Each key in the object is an array of the grouped objects by that key
* @example
* const items = [{type:"food", name:"hotdog"}, {type:"drink", name:"pepsi-cola"}, {type:"food", name:"pizza"}]
* const result = groupArrayByKey (items, 'type')
* @result:
* {
* food: [{type:"food", name:"hotdog"}, {type:"food", name:"pizza"}],
* drink: [{type:"drink", name:"pepsi-cola"}]
* }
*
*/
export const groupArrayByKey = (items, key) => {
return items.reduce((acc, current) => Object.assign(acc, { [current[key]]:( acc[current[key]] || [] ).concat(current) }), {})
}
// slightly more performant version that always returns array values
export const groupBy = (arr, key) => {
return arr.reduce(function(acc, x) {
(acc[x[key]] = acc[x[key]] || []).push(x)
return acc
}, {})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment