Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/array-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,40 @@ This function accepts a variable number of arguments. The length of the returne
__Examples__
- `$zip([1,2,3], [4,5,6])` => `[[1,4] ,[2,5], [3,6]]`
- `$zip([1,2,3],[4,5],[7,8,9])` => `[[1,4,7], [2,5,8]]`

## `$union()`

__Signature:__ `$union(array1, array2)`

Returns a new array containing all distinct elements from both `array1` and `array2`.

__Examples__
- `$union([1,2,3], [3,4,5])` => `[1, 2, 3, 4, 5]`
- `$union([1,2,3], 3)` => `[1, 2, 3]`

## `$intersection()`

__Signature:__ `$intersection(array1, array2)`

Returns a new array containing all distinct elements that are present in both `array1` and `array2`.

__Examples__
- `$intersection([1,2,3], [3,4,5])` => `[3]`

## `$difference()`

__Signature:__ `$difference(array1, array2)`

Returns a new array containing all distinct elements from `array1` that are NOT present in `array2`.

__Examples__
- `$difference([1,2,3], [3,4,5])` => `[1, 2]`

## `$symmetricDifference()`

__Signature:__ `$symmetricDifference(array1, array2)`

Returns a new array containing all distinct elements that are present in either `array1` or `array2`, but NOT in both.

__Examples__
- `$symmetricDifference([1,2,3], [3,4,5])` => `[1, 2, 4, 5]`
96 changes: 95 additions & 1 deletion src/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2047,6 +2047,100 @@ const functions = (() => {
return results;
}

/**
* Helper function to check if an array includes a value using deep equality
* @param {Array} arr - the array to check
* @param {*} value - the value to look for
* @returns {boolean} - true if the value is found, false otherwise
*/
function arrayIncludes(arr, value) {
for (var ii = 0; ii < arr.length; ii++) {
if (deepEquals(value, arr[ii])) {
return true;
}
}
return false;
}

/**
* Set Union
* @param {Array} arg1 - An array or sequence of values
* @param {Array} arg2 - An array or sequence of values
* @returns {Array} - sequence of distinct values from both arrays
*/
function union(arg1, arg2) {
if (typeof arg1 === 'undefined') return distinct.call(this, arg2);
if (typeof arg2 === 'undefined') return distinct.call(this, arg1);
var results = (isSequence(arg1) || isSequence(arg2)) ? this.createSequence() : [];
var appendArgs = arg1.concat(arg2);
for (var ii = 0; ii < appendArgs.length; ii++) {
var value = appendArgs[ii];
if (!arrayIncludes(results, value)) {
results.push(value);
}
}
return results;
}

/**
* Set Intersection
* @param {Array} arg1 - An array or sequence of values
* @param {Array} arg2 - An array or sequence of values
* @returns {Array} - sequence of distinct values present in both arrays
*/
function intersection(arg1, arg2) {
if (typeof arg1 === 'undefined' || typeof arg2 === 'undefined') return undefined;
var results = (isSequence(arg1) || isSequence(arg2)) ? this.createSequence() : [];
for (var ii = 0; ii < arg1.length; ii++) {
var value = arg1[ii];
if (arrayIncludes(arg2, value) && !arrayIncludes(results, value)) {
results.push(value);
}
}
return results;
}

/**
* Set Difference
* @param {Array} arg1 - An array or sequence of values
* @param {Array} arg2 - An array or sequence of values
* @returns {Array} - sequence of distinct values from arg1 not present in arg2
*/
function difference(arg1, arg2) {
if (typeof arg1 === 'undefined') return undefined;
if (typeof arg2 === 'undefined') return distinct.call(this, arg1);
var results = (isSequence(arg1) || isSequence(arg2)) ? this.createSequence() : [];
for (var ii = 0; ii < arg1.length; ii++) {
var value = arg1[ii];
if (!arrayIncludes(arg2, value) && !arrayIncludes(results, value)) {
results.push(value);
}
}
return results;
}

/**
* Set Symmetric Difference
* @param {Array} arg1 - An array or sequence of values
* @param {Array} arg2 - An array or sequence of values
* @returns {Array} - sequence of distinct values present in either arg1 or arg2, but not both
*/
function symmetricDifference(arg1, arg2) {
if (typeof arg1 === 'undefined') return distinct.call(this, arg2);
if (typeof arg2 === 'undefined') return distinct.call(this, arg1);
var results = (isSequence(arg1) || isSequence(arg2)) ? this.createSequence() : [];
var appendArgs = arg1.concat(arg2);
for (var ii = 0; ii < appendArgs.length; ii++) {
var value = appendArgs[ii];
var inArg1 = arrayIncludes(arg1, value);
var inArg2 = arrayIncludes(arg2, value);
if (inArg1 !== inArg2 && !arrayIncludes(results, value)) {
results.push(value);
}
}
return results;
}

/**
* Applies a predicate function to each key/value pair in an object, and returns an object containing
* only the key/value pairs that passed the predicate
Expand Down Expand Up @@ -2083,7 +2177,7 @@ const functions = (() => {
formatNumber, formatBase, number, floor, ceil, round, abs, sqrt, power, random,
boolean, not,
map, zip, filter, single, foldLeft, sift,
keys, lookup, append, exists, spread, merge, reverse, each, error, assert, type, sort, shuffle, distinct,
keys, lookup, append, exists, spread, merge, reverse, each, error, assert, type, sort, shuffle, distinct, union, intersection, difference, symmetricDifference,
base64encode, base64decode, encodeUrlComponent, encodeUrl, decodeUrlComponent, decodeUrl
};
})();
Expand Down
4 changes: 4 additions & 0 deletions src/jsonata.js
Original file line number Diff line number Diff line change
Expand Up @@ -1959,6 +1959,10 @@ var jsonata = (function() {
staticFrame.bind('sort', defineFunction(fn.sort, '<af?:a>'));
staticFrame.bind('shuffle', defineFunction(fn.shuffle, '<a:a>'));
staticFrame.bind('distinct', defineFunction(fn.distinct, '<x:x>'));
staticFrame.bind('union', defineFunction(fn.union, '<a-a:a>'));
staticFrame.bind('intersection', defineFunction(fn.intersection, '<a-a:a>'));
staticFrame.bind('difference', defineFunction(fn.difference, '<a-a:a>'));
staticFrame.bind('symmetricDifference', defineFunction(fn.symmetricDifference, '<a-a:a>'));
staticFrame.bind('base64encode', defineFunction(fn.base64encode, '<s-:s>'));
staticFrame.bind('base64decode', defineFunction(fn.base64decode, '<s-:s>'));
staticFrame.bind('encodeUrlComponent', defineFunction(fn.encodeUrlComponent, '<s-:s>'));
Expand Down
42 changes: 42 additions & 0 deletions test/test-suite/groups/function-difference/difference.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[
{
"expr": "$difference([1,2,3], [3,4,5])",
"data": null,
"bindings": {},
"result": [1, 2]
},
{
"expr": "$difference([1,2,3], 3)",
"data": null,
"bindings": {},
"result": [1, 2]
},
{
"expr": "$difference([1,2,3], nothing)",
"data": null,
"bindings": {},
"result": [1, 2, 3]
},
{
"expr": "$difference(nothing, [1,2,3])",
"data": null,
"bindings": {},
"undefinedResult": true
},
{
"expr": "$difference([{\"a\": 1, \"b\": 2}, 3], [{\"a\": 1, \"b\": 2}, 4])",
"data": null,
"bindings": {},
"result": [3]
},
{
"expr": "$difference(Account.Order.Product.SKU, [\"0406654608\", \"12345\"])",
"dataset": "dataset5",
"bindings": {},
"result": [
"0406634348",
"040657863",
"0406654603"
]
}
]
38 changes: 38 additions & 0 deletions test/test-suite/groups/function-intersection/intersection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"expr": "$intersection([1,2,3], [3,4,5])",
"data": null,
"bindings": {},
"result": [3]
},
{
"expr": "$intersection([1,2,3], 3)",
"data": null,
"bindings": {},
"result": [3]
},
{
"expr": "$intersection([1,2,3], nothing)",
"data": null,
"bindings": {},
"undefinedResult": true
},
{
"expr": "$intersection(nothing, [1,2,3])",
"data": null,
"bindings": {},
"undefinedResult": true
},
{
"expr": "$intersection(Account.Order.Product.SKU, [\"0406654608\", \"12345\"])",
"dataset": "dataset5",
"bindings": {},
"result": "0406654608"
},
{
"expr": "$intersection([{\"a\": 1, \"b\": 2}, 3], [{\"a\": 1, \"b\": 2}, 4])",
"data": null,
"bindings": {},
"result": [{"a": 1, "b": 2}]
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[
{
"expr": "$symmetricDifference([1,2,3], [3,4,5])",
"data": null,
"bindings": {},
"result": [1, 2, 4, 5]
},
{
"expr": "$symmetricDifference([1,2,3], 3)",
"data": null,
"bindings": {},
"result": [1, 2]
},
{
"expr": "$symmetricDifference([1,2,3], nothing)",
"data": null,
"bindings": {},
"result": [1, 2, 3]
},
{
"expr": "$symmetricDifference(nothing, [1,2,3])",
"data": null,
"bindings": {},
"result": [1, 2, 3]
},
{
"expr": "$symmetricDifference([{\"a\":1}, {\"b\":2}], [{\"b\":2}, {\"c\":3}])",
"data": null,
"bindings": {},
"result": [{"a": 1}, {"c": 3}]
},
{
"expr": "$symmetricDifference(Account.Order.Product.SKU, [\"0406654608\", \"12345\"])",
"dataset": "dataset5",
"bindings": {},
"result": [
"0406634348",
"040657863",
"0406654603",
"12345"
]
}
]
38 changes: 38 additions & 0 deletions test/test-suite/groups/function-union/union.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"expr": "$union([1,2,3], [3,4,5])",
"data": null,
"bindings": {},
"result": [1,2,3,4,5]
},
{
"expr": "$union([1,2,3], 3)",
"data": null,
"bindings": {},
"result": [1,2,3]
},
{
"expr": "$union([1,2,3], nothing)",
"data": null,
"bindings": {},
"result": [1,2,3]
},
{
"expr": "$union(nothing, [1,2,3])",
"data": null,
"bindings": {},
"result": [1,2,3]
},
{
"expr": "$union(Account.Order.Product.SKU, [\"0406654608\", \"12345\"])",
"dataset": "dataset5",
"bindings": {},
"result": [
"0406654608",
"0406634348",
"040657863",
"0406654603",
"12345"
]
}
]