jstests/aggregation/extras/utils.js
/**
 * Returns true if both 'al' and 'ar' are arrays of the same length with the same elements according
 * to valueComparator.  Order of the elements within the arrays is not significant.
 *
 * Element comparison uses the anyEq function recursively, which allows for comparing of nested
 * arrays with insignificant order.
 *
 * Use this function if the arguments have nested arrays and the element order is *not* significant
 * when the equivalence is determined. Use assert.sameMembers() in assert.js instead if the
 * arguments have no nested arrays, or the order of the nested arrays is significant for the
 * equivalent assertion.
 */
Returns true if both 'al' and 'ar' are arrays of the same length with the same elements according
to valueComparator.  Order of the elements within the arrays is not significant.

Element comparison uses the anyEq function recursively, which allows for comparing of nested
arrays with insignificant order.

Use this function if the arguments have nested arrays and the element order is *not* significant
when the equivalence is determined. Use assert.sameMembers() in assert.js instead if the
arguments have no nested arrays, or the order of the nested arrays is significant for the
equivalent assertion.
Returns true if both ' al ' and ' ar ' are arrays of the same length with the same elements according to valueComparator . Order of the elements within the arrays is not significant . Element comparison uses the anyEq function recursively which allows for comparing of nested arrays with insignificant order . Use this function if the arguments have nested arrays and the element order is * not * significant when the equivalence is determined . Use assert . sameMembers () in assert . js instead if the arguments have no nested arrays or the order of the nested arrays is significant for the equivalent assertion .
function arrayEq(al, ar, verbose = false, valueComparator, fieldsToSkip = []) {
    const debug = msg => verbose ? print(msg) : null;  
    if (!(al instanceof Array)) {
        debug('arrayEq: al is not an array: ' + tojson(al));
        return false;
    }
    if (!(ar instanceof Array)) {
        debug('arrayEq: ar is not an array: ' + tojson(ar));
        return false;
    }
    if (al.length != ar.length) {
        debug(`arrayEq:  array lengths do not match ${tojson(al)}, ${tojson(ar)}`);
        return false;
    }
    const matchedElementsInRight = new Set();
    for (let leftElem of al) {
        let foundMatch = false;
        for (let i = 0; i < ar.length; ++i) {
            if (!matchedElementsInRight.has(i) &&
                anyEq(leftElem, ar[i], verbose, valueComparator, fieldsToSkip)) {
                matchedElementsInRight.add(i);  
                foundMatch = true;
                break;
            }
        }
        if (!foundMatch) {
            return false;
        }
    }
    return true;
}
function arrayEq ( al , ar , verbose = false , valueComparator , fieldsToSkip = [ ] ) { const debug = msg => verbose ? print ( msg ) : null ; if ( ! ( al instanceof Array ) ) { debug ( 'arrayEq: al is not an array: ' + tojson ( al ) ) ; return false ; } if ( ! ( ar instanceof Array ) ) { debug ( 'arrayEq: ar is not an array: ' + tojson ( ar ) ) ; return false ; } if ( al . length != ar . length ) { debug ( ` ${ tojson ( al ) } ${ tojson ( ar ) } ` ) ; return false ; } const matchedElementsInRight = new Set ( ) ; for ( let leftElem of al ) { let foundMatch = false ; for ( let i = 0 ; i < ar . length ; ++ i ) { if ( ! matchedElementsInRight . has ( i ) && anyEq ( leftElem , ar [ i ] , verbose , valueComparator , fieldsToSkip ) ) { matchedElementsInRight . add ( i ) ; foundMatch = true ; break ; } } if ( ! foundMatch ) { return false ; } } return true ; }
Returns true if both 'al' and 'ar' are arrays of the same length with the same elements according
 to valueComparator.
Returns true if both ' al ' and ' ar ' are arrays of the same length with the same elements according to valueComparator .
// Helper to log 'msg' iff 'verbose' is true. // Check that these are both arrays. // Keep a set of which indexes we've already used to avoid considering [1,1] as equal to [1,2]. // Don't use the same value each time.