Last active
June 3, 2020 08:06
-
-
Save AaronHarris/ceba94c647b4d3e71886c147bbf2d9ab to your computer and use it in GitHub Desktop.
Fun with lodash-fp's flow
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
/** | |
* Nested grouping of a list of objects by multiple nested keys | |
* Unwraps groupByAll(['dataset_name', 'table_name', 'column_name']) to something like: | |
* | |
* ``` | |
* _.flow( | |
* _.groupBy('dataset_name'), | |
* _.mapValues(_.groupBy('table_name')), | |
* _.mapValues(_.mapValues(_.groupBy('column_name'))) | |
* ) | |
* ``` | |
* or its equivalent | |
* | |
* ``` | |
* _.flow( | |
* _.groupBy('dataset_name'), | |
* _.flow(_.groupBy, _.mapValues)('table_name') | |
* _.flow(_.groupBy, _.mapalues, _.mapValues)('column_name') | |
* ) | |
* ``` | |
* Source: [GitHub](https://github.com/lodash/lodash/issues/3894#issuecomment-409689045) | |
*/ | |
const groupByAll = (iteratees: any) => | |
fp.flow( | |
(fp.map as any).convert({cap:false})( | |
(iteratee: any, i: any) => | |
fp.flow(fp.groupBy, ...fp.times(() => fp.mapValues, i))(iteratee), | |
iteratees | |
) | |
); | |
/** | |
* @todo This is untested | |
* Unwraps groupByAllThen(['dataset_name', 'table_name', 'column_name'], _.map('old_column_name')) to something like: | |
* | |
* @example | |
* ``` | |
* _.flow( | |
* _.groupBy('dataset_name'), | |
* _.mapValues(_.groupBy('table_name')), | |
* _.mapValues(_.mapValues(_.groupBy('column_name'))), | |
* _.mapValues(_.mapValues(_.map('old_column_name'))) | |
* ) | |
* ``` | |
* | |
* @example | |
* groupByAllThen( | |
* ['dataset_name', 'table_name', 'column_name'], | |
* fp.flow( | |
* fp.map('old_column_name'), | |
* fp.flatMap(fp.split(',')), | |
* fp.map(fp.trim) | |
* ) | |
* ), | |
* fp.pickBy(sizeGt1), | |
* fp.pickBy(fp.negate(fp.isEmpty)) | |
* ) | |
* | |
* becomes | |
* | |
* ``` | |
* _.flow( | |
* _.groupBy('dataset_name'), | |
* _.mapValues(_.groupBy('table_name')), | |
* _.mapValues(_.mapValues(_.groupBy('column_name'))), | |
* _.mapValues(_.mapValues(_.mapValues(_.flow( // GroupAndMapAndSplit | |
* fp.map('old_column_name'), | |
* fp.flatMap(fp.split(',')), | |
* fp.map(fp.trim) | |
* )))), | |
* _.mapValues(_.mapValues(fp.pickBy(sizeGt1))), // KeepOnlyMultiple | |
* _.mapValues(_.pickBy(_.negate(_.isEmpty))) | |
* | |
*/ | |
const groupByAllThen = (iteratees: any, ...ops: any) => | |
fp.flow( | |
(fp.map as any).convert({cap:false})( | |
(iteratee: any, i: any) => | |
fp.flow(fp.groupBy, ...fp.times(() => fp.mapValues, i))(iteratee), | |
iteratees | |
), | |
(fp.map as any).convert({cap:false})( | |
(op: any, i: any) => | |
fp.flow(op, ...fp.times(() => fp.mapValues, iteratees.length-i)), | |
ops | |
), | |
); | |
const isObjOrArr = (obj: any) => fp.isPlainObject(obj) || fp.isArray(obj); | |
/** | |
* Like compact for arrays, but removes keys that point to empty values | |
* @param object | |
* @returns a | |
*/ | |
const compactObj = fp.pickBy(fp.cond([ | |
[isObjOrArr, fp.negate(fp.isEmpty)], | |
[fp.isNil, fp.stubFalse], | |
[fp.stubTrue, fp.stubTrue] | |
])); | |
// compactObjDeep has some kinks due to isEmpty returning false for numbers and booleans | |
const compactObjDeep = (obj: any): any => { | |
if (fp.isArray(obj)) { | |
if (fp.isEmpty(obj)) { return undefined; } | |
return fp.compact(fp.map(compactObjDeep, obj)); | |
} | |
if (fp.isPlainObject(obj)) { | |
if (fp.isEmpty(obj)) { return undefined; } | |
return compactObj(fp.mapValues(compactObjDeep, obj as any)); | |
} | |
return obj; | |
}; | |
/** | |
* @note This works with the non-fp lodash, but I feel is prone to bugs | |
* @param array of objects | |
* @return a unique list of the mapped elements | |
* @example _.mapUniq(array, 'column_name') | |
const mapUniq = _.flow(_.map, _.uniqBy); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment