Created
December 19, 2023 21:53
-
-
Save ricardobeat/040af80971273f5abd71c2bfcfdfdd50 to your computer and use it in GitHub Desktop.
lodash 'simple group by'
This file contains 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
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L9393C5-L9399C8 | |
var groupBy = createAggregator(function(result, value, key) { | |
if (hasOwnProperty.call(result, key)) { | |
result[key].push(value); | |
} else { | |
baseAssignValue(result, key, [value]); | |
} | |
}); | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L4818C5-L4825C6 | |
function createAggregator(setter, initializer) { | |
return function(collection, iteratee) { | |
var func = isArray(collection) ? arrayAggregator : baseAggregator, | |
accumulator = initializer ? initializer() : {}; | |
return func(collection, setter, getIteratee(iteratee, 2), accumulator); | |
}; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11286C5-L11286C33 | |
var isArray = Array.isArray; | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L491C2-L500C4 | |
function arrayAggregator(array, setter, iteratee, accumulator) { | |
var index = -1, | |
length = array == null ? 0 : array.length; | |
while (++index < length) { | |
var value = array[index]; | |
setter(accumulator, value, iteratee(value), array); | |
} | |
return accumulator; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L15531C3-L15533C6 | |
function iteratee(func) { | |
return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG)); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3458C4-L3473C6 | |
function baseIteratee(value) { | |
// Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. | |
// See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. | |
if (typeof value == 'function') { | |
return value; | |
} | |
if (value == null) { | |
return identity; | |
} | |
if (typeof value == 'object') { | |
return isArray(value) | |
? baseMatchesProperty(value[0], value[1]) | |
: baseMatches(value); | |
} | |
return property(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3573C1-L3583C6 | |
function baseMatchesProperty(path, srcValue) { | |
if (isKey(path) && isStrictComparable(srcValue)) { | |
return matchesStrictComparable(toKey(path), srcValue); | |
} | |
return function(object) { | |
var objValue = get(object, path); | |
return (objValue === undefined && objValue === srcValue) | |
? hasIn(object, path) | |
: baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); | |
}; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3555 | |
function baseMatches(source) { | |
var matchData = getMatchData(source); | |
if (matchData.length == 1 && matchData[0][2]) { | |
return matchesStrictComparable(matchData[0][0], matchData[0][1]); | |
} | |
return function(object) { | |
return object === source || baseIsMatch(object, source, matchData); | |
}; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L5951 | |
function getMatchData(object) { | |
var result = keys(object), | |
length = result.length; | |
while (length--) { | |
var key = result[length], | |
value = object[key]; | |
result[length] = [key, value, isStrictComparable(value)]; | |
} | |
return result; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L13306 | |
function keys(object) { | |
return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11332 | |
function isArrayLike(value) { | |
return value != null && isLength(value.length) && !isFunction(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11713 | |
function isLength(value) { | |
return typeof value == 'number' && | |
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11647 | |
function isFunction(value) { | |
if (!isObject(value)) { | |
return false; | |
} | |
// The use of `Object#toString` avoids issues with the `typeof` operator | |
// in Safari 9 which returns 'object' for typed arrays and other constructors. | |
var tag = baseGetTag(value); | |
return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L11743 | |
function isObject(value) { | |
var type = typeof value; | |
return value != null && (type == 'object' || type == 'function'); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3063 | |
function baseGetTag(value) { | |
if (value == null) { | |
return value === undefined ? undefinedTag : nullTag; | |
} | |
return (symToStringTag && symToStringTag in Object(value)) | |
? getRawTag(value) | |
: objectToString(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L5984 | |
function getRawTag(value) { | |
var isOwn = hasOwnProperty.call(value, symToStringTag), | |
tag = value[symToStringTag]; | |
try { | |
value[symToStringTag] = undefined; | |
var unmasked = true; | |
} catch (e) {} | |
var result = nativeObjectToString.call(value); | |
if (unmasked) { | |
if (isOwn) { | |
value[symToStringTag] = tag; | |
} else { | |
delete value[symToStringTag]; | |
} | |
} | |
return result; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L6533 | |
function objectToString(value) { | |
return nativeObjectToString.call(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L6393 | |
function isStrictComparable(value) { | |
return value === value && !isObject(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L2383 | |
function arrayLikeKeys(value, inherited) { | |
var isArr = isArray(value), | |
isArg = !isArr && isArguments(value), | |
isBuff = !isArr && !isArg && isBuffer(value), | |
isType = !isArr && !isArg && !isBuff && isTypedArray(value), | |
skipIndexes = isArr || isArg || isBuff || isType, | |
result = skipIndexes ? baseTimes(value.length, String) : [], | |
length = result.length; | |
for (var key in value) { | |
if ((inherited || hasOwnProperty.call(value, key)) && | |
!(skipIndexes && ( | |
// Safari 9 has enumerable `arguments.length` in strict mode. | |
key == 'length' || | |
// Node.js 0.10 has enumerable non-index properties on buffers. | |
(isBuff && (key == 'offset' || key == 'parent')) || | |
// PhantomJS 2 has enumerable non-index properties on typed arrays. | |
(isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || | |
// Skip index properties. | |
isIndex(key, length) | |
))) { | |
result.push(key); | |
} | |
} | |
return result; | |
} | |
// https://github.com/lodash/lodash/blob/main/src/isArguments.ts#L19 | |
function isArguments(value) { | |
return isObjectLike(value) && getTag(value) === '[object Arguments]'; | |
} | |
// https://github.com/lodash/lodash/blob/main/src/isObjectLike.ts#L23 | |
function isObjectLike(value) { | |
return typeof value === 'object' && value !== null; | |
} | |
// https://github.com/lodash/lodash/blob/main/src/.internal/getTag.ts#L10 | |
function getTag(value) { | |
if (value == null) { | |
return value === undefined ? '[object Undefined]' : '[object Null]' | |
} | |
return toString.call(value) | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L6393 | |
function isStrictComparable(value) { | |
return value === value && !isObject(value); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3357 | |
function baseIsMatch(object, source, matchData, customizer) { | |
var index = matchData.length, | |
length = index, | |
noCustomizer = !customizer; | |
if (object == null) { | |
return !length; | |
} | |
object = Object(object); | |
while (index--) { | |
var data = matchData[index]; | |
if ((noCustomizer && data[2]) | |
? data[1] !== object[data[0]] | |
: !(data[0] in object) | |
) { | |
return false; | |
} | |
} | |
while (++index < length) { | |
data = matchData[index]; | |
var key = data[0], | |
objValue = object[key], | |
srcValue = data[1]; | |
if (noCustomizer && data[2]) { | |
if (objValue === undefined && !(key in object)) { | |
return false; | |
} | |
} else { | |
var stack = new Stack; | |
if (customizer) { | |
var result = customizer(objValue, srcValue, key, object, source, stack); | |
} | |
if (!(result === undefined | |
? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) | |
: result | |
)) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3267 | |
function baseIsEqual(value, other, bitmask, customizer, stack) { | |
if (value === other) { | |
return true; | |
} | |
if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { | |
return value !== value && other !== other; | |
} | |
return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L3291 | |
function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { | |
var objIsArr = isArray(object), | |
othIsArr = isArray(other), | |
objTag = objIsArr ? arrayTag : getTag(object), | |
othTag = othIsArr ? arrayTag : getTag(other); | |
objTag = objTag == argsTag ? objectTag : objTag; | |
othTag = othTag == argsTag ? objectTag : othTag; | |
var objIsObj = objTag == objectTag, | |
othIsObj = othTag == objectTag, | |
isSameTag = objTag == othTag; | |
if (isSameTag && isBuffer(object)) { | |
if (!isBuffer(other)) { | |
return false; | |
} | |
objIsArr = true; | |
objIsObj = false; | |
} | |
if (isSameTag && !objIsObj) { | |
stack || (stack = new Stack); | |
return (objIsArr || isTypedArray(object)) | |
? equalArrays(object, other, bitmask, customizer, equalFunc, stack) | |
: equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); | |
} | |
if (!(bitmask & COMPARE_PARTIAL_FLAG)) { | |
var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), | |
othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); | |
if (objIsWrapped || othIsWrapped) { | |
var objUnwrapped = objIsWrapped ? object.value() : object, | |
othUnwrapped = othIsWrapped ? other.value() : other; | |
stack || (stack = new Stack); | |
return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); | |
} | |
} | |
if (!isSameTag) { | |
return false; | |
} | |
stack || (stack = new Stack); | |
return equalObjects(object, other, bitmask, customizer, equalFunc, stack); | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L5613 | |
function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { | |
var isPartial = bitmask & COMPARE_PARTIAL_FLAG, | |
arrLength = array.length, | |
othLength = other.length; | |
if (arrLength != othLength && !(isPartial && othLength > arrLength)) { | |
return false; | |
} | |
// Assume cyclic values are equal. | |
var stacked = stack.get(array); | |
if (stacked && stack.get(other)) { | |
return stacked == other; | |
} | |
var index = -1, | |
result = true, | |
seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; | |
stack.set(array, other); | |
stack.set(other, array); | |
// Ignore non-index properties. | |
while (++index < arrLength) { | |
var arrValue = array[index], | |
othValue = other[index]; | |
if (customizer) { | |
var compared = isPartial | |
? customizer(othValue, arrValue, index, other, array, stack) | |
: customizer(arrValue, othValue, index, array, other, stack); | |
} | |
if (compared !== undefined) { | |
if (compared) { | |
continue; | |
} | |
result = false; | |
break; | |
} | |
// Recursively compare arrays (susceptible to call stack limits). | |
if (seen) { | |
if (!arraySome(other, function(othValue, othIndex) { | |
if (!cacheHas(seen, othIndex) && | |
(arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { | |
return seen.push(othIndex); | |
} | |
})) { | |
result = false; | |
break; | |
} | |
} else if (!( | |
arrValue === othValue || | |
equalFunc(arrValue, othValue, bitmask, customizer, stack) | |
)) { | |
result = false; | |
break; | |
} | |
} | |
stack['delete'](array); | |
stack['delete'](other); | |
return result; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L721 | |
function arraySome(array, predicate) { | |
var index = -1, | |
length = array == null ? 0 : array.length; | |
while (++index < length) { | |
if (predicate(array[index], index, array)) { | |
return true; | |
} | |
} | |
return false; | |
} | |
// https://github.com/lodash/lodash/blob/4.17.15/lodash.js#L5691 | |
function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { | |
switch (tag) { | |
case dataViewTag: | |
if ((object.byteLength != other.byteLength) || | |
(object.byteOffset != other.byteOffset)) { | |
return false; | |
} | |
object = object.buffer; | |
other = other.buffer; | |
case arrayBufferTag: | |
if ((object.byteLength != other.byteLength) || | |
!equalFunc(new Uint8Array(object), new Uint8Array(other))) { | |
return false; | |
} | |
return true; | |
case boolTag: | |
case dateTag: | |
case numberTag: | |
// Coerce booleans to `1` or `0` and dates to milliseconds. | |
// Invalid dates are coerced to `NaN`. | |
return eq(+object, +other); | |
case errorTag: | |
return object.name == other.name && object.message == other.message; | |
case regexpTag: | |
case stringTag: | |
// Coerce regexes to strings and treat strings, primitives and objects, | |
// as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring | |
// for more details. | |
return object == (other + ''); | |
case mapTag: | |
var convert = mapToArray; | |
case setTag: | |
var isPartial = bitmask & COMPARE_PARTIAL_FLAG; | |
convert || (convert = setToArray); | |
if (object.size != other.size && !isPartial) { | |
return false; | |
} | |
// Assume cyclic values are equal. | |
var stacked = stack.get(object); | |
if (stacked) { | |
return stacked == other; | |
} | |
bitmask |= COMPARE_UNORDERED_FLAG; | |
// Recursively compare objects (susceptible to call stack limits). | |
stack.set(object, other); | |
var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); | |
stack['delete'](object); | |
return result; | |
case symbolTag: | |
if (symbolValueOf) { | |
return symbolValueOf.call(object) == symbolValueOf.call(other); | |
} | |
} | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment