@@ -912,3 +912,133 @@ regex.extractAll('id:123, id:456', 'assa') == []
912912
913913regex.extractAll('testuser@testdomain', '(.*)@([^.]*)') \\ Runtime Error multiple capture group
914914```
915+ ## TwoVarComprehensions
916+
917+ TwoVarComprehensions introduces support for two-variable comprehensions.
918+
919+ The two-variable form of comprehensions looks similar to the one-variable
920+ counterparts. Where possible, the same macro names were used and additional
921+ macro signatures added. The notable distinction for two-variable comprehensions
922+ is the introduction of ` transformList ` , ` transformMap ` , and ` transformMapEntry `
923+ support for list and map types rather than the more traditional ` map ` and
924+ ` filter ` macros.
925+
926+ ### All
927+
928+ Comprehension which tests whether all elements in the list or map satisfy a
929+ given predicate. The ` all ` macro evaluates in a manner consistent with logical
930+ AND and will short-circuit when encountering a ` false ` value.
931+
932+ <list>.all(indexVar, valueVar, <predicate>) -> bool
933+ <map>.all(keyVar, valueVar, <predicate>) -> bool
934+
935+ Examples:
936+
937+ [1, 2, 3].all(i, j, i < j) // returns true
938+ {'hello': 'world', 'taco': 'taco'}.all(k, v, k != v) // returns false
939+
940+ // Combines two-variable comprehension with single variable
941+ {'h': ['hello', 'hi'], 'j': ['joke', 'jog']}
942+ .all(k, vals, vals.all(v, v.startsWith(k))) // returns true
943+
944+ ### Exists
945+
946+ Comprehension which tests whether any element in a list or map exists which
947+ satisfies a given predicate. The ` exists ` macro evaluates in a manner consistent
948+ with logical OR and will short-circuit when encountering a ` true ` value.
949+
950+ <list>.exists(indexVar, valueVar, <predicate>) -> bool
951+ <map>.exists(keyVar, valueVar, <predicate>) -> bool
952+
953+ Examples:
954+
955+ {'greeting': 'hello', 'farewell': 'goodbye'}
956+ .exists(k, v, k.startsWith('good') || v.endsWith('bye')) // returns true
957+ [1, 2, 4, 8, 16].exists(i, v, v == 1024 && i == 10) // returns false
958+
959+ ### Exists_One
960+
961+ Comprehension which tests whether exactly one element in a list or map exists
962+ which satisfies a given predicate expression. The ` exists_one ` macro
963+ comprehension does not short-circuit in keeping with the one-variable semantics.
964+
965+ <list>.existsOne(indexVar, valueVar, <predicate>)
966+ <map>.existsOne(keyVar, valueVar, <predicate>)
967+
968+ Examples:
969+
970+ [1, 2, 1, 3, 1, 4].existsOne(i, v, i == 1 || v == 1) // returns false
971+ [1, 1, 2, 2, 3, 3].existsOne(i, v, i == 2 && v == 2) // returns true
972+ {'i': 0, 'j': 1, 'k': 2}.existsOne(i, v, i == 'l' || v == 1) // returns true
973+
974+ ### TransformList
975+
976+ Comprehension which converts a map or a list into a list value. The output
977+ expression of the comprehension determines the contents of the output list.
978+ Elements in the list may optionally be filtered according to a predicate
979+ expression, where elements that satisfy the predicate are transformed.
980+
981+ <list>.transformList(indexVar, valueVar, <transform>)
982+ <list>.transformList(indexVar, valueVar, <filter>, <transform>)
983+ <map>.transformList(keyVar, valueVar, <transform>)
984+ <map>.transformList(keyVar, valueVar, <filter>, <transform>)
985+
986+ Examples:
987+
988+ [1, 2, 3].transformList(indexVar, valueVar,
989+ (indexVar * valueVar) + valueVar) // returns [1, 4, 9]
990+ [1, 2, 3].transformList(indexVar, valueVar, indexVar % 2 == 0
991+ (indexVar * valueVar) + valueVar) // returns [1, 9]
992+ {'greeting': 'hello', 'farewell': 'goodbye'}
993+ .transformList(k, _, k) // returns ['greeting', 'farewell']
994+ {'greeting': 'hello', 'farewell': 'goodbye'}
995+ .transformList(_, v, v) // returns ['hello', 'goodbye']
996+
997+ ### TransformMap
998+
999+ Comprehension which converts a map or a list into a map value. The output
1000+ expression of the comprehension determines the value of the output map entry;
1001+ however, the key remains fixed. Elements in the map may optionally be filtered
1002+ according to a predicate expression, where elements that satisfy the predicate
1003+ are transformed.
1004+
1005+ <list>.transformMap(indexVar, valueVar, <transform>)
1006+ <list>.transformMap(indexVar, valueVar, <filter>, <transform>)
1007+ <map>.transformMap(keyVar, valueVar, <transform>)
1008+ <map>.transformMap(keyVar, valueVar, <filter>, <transform>)
1009+
1010+ Examples:
1011+
1012+ [1, 2, 3].transformMap(indexVar, valueVar,
1013+ (indexVar * valueVar) + valueVar) // returns {0: 1, 1: 4, 2: 9}
1014+ [1, 2, 3].transformMap(indexVar, valueVar, indexVar % 2 == 0
1015+ (indexVar * valueVar) + valueVar) // returns {0: 1, 2: 9}
1016+ {'greeting': 'hi'}.transformMap(k, v, v + '!') // returns {'greeting': 'hi!'}
1017+
1018+ ### TransformMapEntry
1019+
1020+ Comprehension which converts a map or a list into a map value; however, this
1021+ transform expects the entry expression be a map literal. If the transform
1022+ produces an entry which duplicates a key in the target map, the comprehension
1023+ will error. Note, that key equality is determined using CEL equality which
1024+ asserts that numeric values which are equal, even if they don't have the same
1025+ type will cause a key collision.
1026+
1027+ Elements in the map may optionally be filtered according to a predicate
1028+ expression, where elements that satisfy the predicate are transformed.
1029+
1030+ <list>.transformMapEntry(indexVar, valueVar, <transform>)
1031+ <list>.transformMapEntry(indexVar, valueVar, <filter>, <transform>)
1032+ <map>.transformMapEntry(keyVar, valueVar, <transform>)
1033+ <map>.transformMapEntry(keyVar, valueVar, <filter>, <transform>)
1034+
1035+ Examples:
1036+
1037+ {'greeting': 'hello'}.transformMapEntry(keyVar, valueVar,
1038+ {valueVar: keyVar}) // returns {'hello': 'greeting'}
1039+ // reverse lookup, require all values in list be unique
1040+ [1, 2, 3].transformMapEntry(indexVar, valueVar,
1041+ {valueVar: indexVar}) // returns {1:0, 2:1, 3:2}
1042+
1043+ {'greeting': 'aloha', 'farewell': 'aloha'}
1044+ .transformMapEntry(k, v, {v: k}) // error, duplicate key
0 commit comments