Last active
May 21, 2025 23:49
-
-
Save psenger/38d2d6c7601b65fa92585abd1bc2a34a to your computer and use it in GitHub Desktop.
[Bucketize / Count Occurrences / Group / Separate an array of objects by a value as defined by the attribute, Ways to Sort] #JavaScript #Array #bucket #groupBy #collect #bag #counter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Buckets of Data, with two Items appearing at the top of the list. | |
| // note that OOO and AAA are at the top, whilst everything else is sorted | |
| // Desired outcome: | |
| // ------------------------------------------------------------------------------------------------- | |
| // OOO [ { type: 'OOO', attributes: {} }, { type: 'OOO', attributes: {} } ] | |
| // AAA [ { type: 'AAA', attributes: {} } ] | |
| // BBB [ { type: 'BBB', attributes: {} }, { type: 'BBB', attributes: {} } ] | |
| // ZZZ [ { type: 'ZZZ', attributes: {} }, { type: 'ZZZ', attributes: {} } ] | |
| const desiredFirstItem = 'OOO' | |
| const desiredSecondItem = 'AAA' | |
| const data = [ | |
| { | |
| type: 'ZZZ', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'AAA', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'OOO', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'BBB', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'BBB', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'ZZZ', | |
| attributes: {} | |
| }, | |
| { | |
| type: 'OOO', | |
| attributes: {} | |
| } | |
| ] | |
| // This works, as long as there is not an `A` in the list. If there was, you might need to make | |
| // a map entry that moved `A` : `AA` and so on. | |
| const ALPHA = { | |
| } | |
| ALPHA[desiredFirstItem] = 'A' | |
| ALPHA[desiredSecondItem] = 'B' | |
| // create a Bucket / Map of type, values are array of objects | |
| const groupedOldWay = data.reduce((acc, o) => { | |
| acc[o.type] = acc[o.type] || [] | |
| acc[o.type] = [...acc[o.type], o] | |
| return acc | |
| }, {}) | |
| // Since 2025 / [EcmaScript 2026](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.groupby) | |
| const grouped = Object.groupBy(data, obj => obj.type) | |
| Object.entries(grouped /** groupedOldWay **/ ) | |
| .sort(([a],[b])=>{ | |
| // I want `OOO` and `AAA` to appear at the top of the list, in that order, and everything else, | |
| // in alphabetical order | |
| // I found this technique to work best. | |
| // the positive 1 result indicates a change in order is needed. | |
| // The negative -1 or zero result means no change needed. | |
| return (ALPHA[a]?ALPHA[a]:a).localeCompare(ALPHA[b]?ALPHA[b]:b) | |
| }) | |
| .map(([key, value]) => { | |
| console.log(key, value) | |
| return [key, value] | |
| }) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Count Occurrences of values in a list. Referred to as a Bag or HashBag | |
| * Desired outcome: | |
| * ------------------------------------------------------------------------------------------------- | |
| * const CountEmails = { | |
| * 'READ': 1, | |
| * 'UNREAD': 2, | |
| * 'SPAM': 3, | |
| * 'DRAFT': 0 | |
| * } | |
| * ---- | |
| */ | |
| const options = { flagA: false, flagB: true } | |
| const values = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; | |
| const countOccurrencesOldWay = (m) => m.reduce(function (acc, curr) { | |
| acc[curr] = acc[curr] ? acc[curr] : 0 | |
| acc[curr]++ | |
| return acc | |
| }, {}) | |
| // Since 2025 / [EcmaScript 2026](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.groupby) | |
| const countOccurrences = (m) => { | |
| const grouped = Object.groupBy(m, x => x); | |
| return Object.fromEntries( | |
| Object.entries(grouped).map(([key, array]) => [key, array.length]) | |
| ); | |
| } | |
| const countOccurrencesOfObjectValues = (o) => countOccurrences(Object.values(o)) | |
| console.log( 'Occurrences Of Array =',JSON.stringify(countOccurrences(values) , null, 4 ) ); | |
| // Occurrences Of Array = { | |
| // "2": 5, | |
| // "4": 1, | |
| // "5": 3, | |
| // "9": 1 | |
| // } | |
| console.log('Occurrences Of Object Values =',JSON.stringify(countOccurrencesOfObjectValues(options) , null, 4 ) ); | |
| // Occurrences Of Object Values = { | |
| // "false": 1, | |
| // "true": 1 | |
| // } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Bucketize / Group / Separate objects into buckets or groups, to categorize. Key is determined by the passed attribute value. | |
| * Desired outcome: | |
| * ------------------------------------------------------------------------------------------------- | |
| * { | |
| * "bob": [ | |
| * {"id": 1, "name": "bob"} | |
| * ], | |
| * "larry": [ | |
| * {"id": 2, "name": "larry"}, | |
| * {"id": 6, "name": "larry"} | |
| * ], | |
| * "dan": [ | |
| * {"id": 3, "name": "dan"}, | |
| * {"id": 4, "name": "dan"} | |
| * ], | |
| * "tom": [ | |
| * {"id": 5, "name": "tom"} | |
| * ], | |
| * "undefined": [ | |
| * {"id": 7} | |
| * ] | |
| * } | |
| * ---- | |
| */ | |
| /** | |
| * Bucket / Group objects in an array by the value of the passed attribute. | |
| * @param {[*]} objects - array of objects | |
| * @param {string} attributeName - the attribute name | |
| * @deprecated since EcmaScript 2026 | |
| * @return {T} | |
| */ | |
| const bucketByAttributeOldWay = ( objects, attributeName ) => { | |
| return (objects||[]) | |
| .reduce((previousValue,currentValue,currentIndex,array) => { | |
| if( currentValue && previousValue.hasOwnProperty( currentValue[attributeName] ) ) { | |
| previousValue[ currentValue[attributeName] ].push( currentValue ); | |
| } else if ( currentValue ) { | |
| previousValue[ currentValue[attributeName] ] = [ currentValue ]; | |
| } | |
| return previousValue | |
| }, {}); | |
| } | |
| // | |
| /** | |
| * Bucket / Group objects in an array by the value of the passed attribute. | |
| * Since 2025 / [EcmaScript 2026](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.groupby) | |
| * @param {[*]} objects - array of objects | |
| * @param {string} attributeName - the attribute name | |
| * @deprecated since EcmaScript 2026 | |
| * @return {T} | |
| */ | |
| const bucketByAttribute = (objects, attributeName) => { | |
| return Object.groupBy(objects || [], obj => obj?.[attributeName]); | |
| }; | |
| const data = [ | |
| {id: 1, name: 'bob'}, | |
| {id: 2, name: 'larry'}, | |
| {id: 3, name: 'dan'}, | |
| {id: 4, name: 'dan'}, | |
| {id: 5, name: 'tom'}, | |
| {id: 6, name: 'larry'}, | |
| {id: 7} | |
| ] | |
| console.log(JSON.stringify(bucketByAttribute(data, 'name'), null, 4)); | |
| /** | |
| { | |
| "bob": [ | |
| { | |
| "id": 1, | |
| "name": "bob" | |
| } | |
| ], | |
| "larry": [ | |
| { | |
| "id": 2, | |
| "name": "larry" | |
| }, | |
| { | |
| "id": 6, | |
| "name": "larry" | |
| } | |
| ], | |
| "dan": [ | |
| { | |
| "id": 3, | |
| "name": "dan" | |
| }, | |
| { | |
| "id": 4, | |
| "name": "dan" | |
| } | |
| ], | |
| "tom": [ | |
| { | |
| "id": 5, | |
| "name": "tom" | |
| } | |
| ], | |
| "undefined": [ | |
| { | |
| "id": 7 | |
| } | |
| ] | |
| } | |
| **/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const number = [99, 87, 3]; | |
| const letters = ['z', 'g', 'c']; | |
| // Ascending order | |
| // [ 3, 87, 99 ] | |
| // [ 'c', 'g', 'z' ] | |
| console.log(number.sort(function(a, b){return a - b})); | |
| console.log(letters.sort(function(a, b){return a.localeCompare(b)})); | |
| // Descending order / or you can call reverse on Ascending order | |
| // [ 99, 87, 3 ] | |
| // [ 'z', 'g', 'c' ] | |
| console.log(number.sort(function(a, b){return b - a})); | |
| console.log(letters.sort(function(a, b){return b.localeCompare(a)})); | |
| // using the reverse() method | |
| console.log(number.sort(function(a, b){return a - b}).reverse()); | |
| console.log(letters.sort(function(a, b){return a.localeCompare(b)}).reverse()); | |
| const strings = ['č','é','A','b','Đ']; | |
| const defaultSort = Array.from(strings).sort(); | |
| const simpleSort = Array.from(strings).sort((a, b) => a - b); | |
| const localeSort = Array.from(strings).sort((a, b) => { | |
| return a.localCompare(b, 'en', { sensitivity: 'base' }); | |
| }); | |
| console.log(defaultSort); | |
| console.log(simpleSort); | |
| console.log(localeSort); | |
| /** | |
| // Pseudo Code | |
| if (a is more than b) return 1 | |
| if (a is less than b) return -1 | |
| return 0 | |
| **/ | |
| number.sort( function( a , b){ | |
| if(a > b) return 1; | |
| if(a < b) return -1; | |
| return 0; | |
| }); | |
| // [ 3, 87, 99 ] | |
| console.log(numbers); | |
| // this comparator works the same way (a, b) => a - b | |
| // case insensitive sort | |
| letters.sort(function (a, b) { | |
| let x = a.toUpperCase(), | |
| y = b.toUpperCase(); | |
| return x === y ? 0 : x > y ? 1 : -1; | |
| }); | |
| // [ 'c', 'g', 'z' ] | |
| console.log(letters); | |
| // Sorting by date, where object x and y have hireDate | |
| /** | |
| let a = new Date(x.hireDate), | |
| b = new Date(y.hireDate); | |
| return a - b; | |
| **/ | |
| // 0-Large Number.... then Negative Large number to small negative number | |
| // put negative numbers at the end of the array | |
| const arr = [12, 50, 6, -1, 0, 99, -100 -9] | |
| const sorted = arr. sort ((a, b) => { | |
| if (a < 0 && b < 0) { // if both b and a are negative, sort is normal | |
| return a - b | |
| } else if (a < 0 || b < 0) { // if one value is negative, sort in opposite direction | |
| return b - a | |
| } else { | |
| return a - b // sort like normal positive first, negative second | |
| } | |
| } | |
| ) | |
| console. log (sorted) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment