Skip to content

Commit 3389677

Browse files
authored
Dict.assignMany/concat/concatMany/concatAll, Array.concatAll (#8364)
* add assignMany, concat, and concatMany for Dict * changelog * add Dict.concatAll * add Array.concatAll * remove dict spread tests * update test output
1 parent c8d05be commit 3389677

12 files changed

Lines changed: 550 additions & 16 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#### :rocket: New Feature
2323

2424
- Rewatch: add `--prod` flag to `build`, `watch`, and `clean` to skip dev-dependencies and dev sources (`"type": "dev"`), enabling builds in environments where dev packages aren't installed (e.g. after `pnpm install --prod`). https://github.com/rescript-lang/rescript/pull/8347
25+
- Add `Dict.assignMany`, `Dict.concat`, `Dict.concatMany`, `Dict.concatAll`, `Array.concatAll` to the stdlib. https://github.com/rescript-lang/rescript/pull/8364
2526

2627
#### :bug: Bug fix
2728

packages/@rescript/runtime/Stdlib_Array.res

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ external removeInPlace: (array<'a>, int, @as(1) _) => unit = "splice"
145145

146146
@send external concat: (array<'a>, array<'a>) => array<'a> = "concat"
147147
@variadic @send external concatMany: (array<'a>, array<array<'a>>) => array<'a> = "concat"
148+
let concatAll = arrays => concatMany([], arrays)
148149

149150
@send external flat: array<array<'a>> => array<'a> = "flat"
150151

packages/@rescript/runtime/Stdlib_Array.resi

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,23 @@ Console.log(someArray) // ["hi", "hello", "yay", "wehoo"]
577577
@variadic @send
578578
external concatMany: (array<'a>, array<array<'a>>) => array<'a> = "concat"
579579

580+
/**
581+
`concatAll(arrays)` concatenates all arrays in `arrays`, creating a new array.
582+
583+
See [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN.
584+
585+
## Examples
586+
```rescript
587+
let arrays = [["hi", "hello"], ["yay"], ["wehoo"]]
588+
589+
let result = Array.concatAll(arrays)
590+
591+
arrays == [["hi", "hello"], ["yay"], ["wehoo"]]
592+
result == ["hi", "hello", "yay", "wehoo"]
593+
```
594+
*/
595+
let concatAll: array<array<'a>> => array<'a>
596+
580597
/**
581598
`flat(arrays)` concatenates an array of arrays into a single array.
582599

packages/@rescript/runtime/Stdlib_Dict.res

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ external fromIterable: Stdlib_Iterable.t<(string, 'a)> => dict<'a> = "Object.fro
2323

2424
@val external assign: (dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
2525

26+
@variadic @val external assignMany: (dict<'a>, array<dict<'a>>) => dict<'a> = "Object.assign"
27+
28+
@val external concat: (@as(json`{}`) _, dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
29+
30+
@variadic @val
31+
external concatMany: (@as(json`{}`) _, dict<'a>, array<dict<'a>>) => dict<'a> = "Object.assign"
32+
33+
@variadic @val external concatAll: (@as(json`{}`) _, array<dict<'a>>) => dict<'a> = "Object.assign"
34+
2635
@val external copy: (@as(json`{}`) _, dict<'a>) => dict<'a> = "Object.assign"
2736

2837
// Use %raw to support for..in which is a ~10% faster than .forEach

packages/@rescript/runtime/Stdlib_Dict.resi

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ external valuesToArray: dict<'a> => array<'a> = "Object.values"
222222
/**
223223
`assign(dictionary1, dictionary2)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges dictionary2 into dictionary1, and returns dictionary1.
224224
225-
Beware this will *mutate* dictionary1. If you're looking for a way to copy a dictionary, check out `Dict.copy`.
225+
Beware this will *mutate* dictionary1. If you're looking for a fresh merged dictionary instead, check out `Dict.concat`.
226226
227227
## Examples
228228
```rescript
@@ -242,6 +242,88 @@ Console.log(dict1->Dict.keysToArray) // Logs `["firstKey", "someKey", "someKey2"
242242
@val
243243
external assign: (dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
244244

245+
/**
246+
`assignMany(target, sources)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges each dictionary in `sources` into `target`, and returns `target`.
247+
248+
Beware this will *mutate* `target`. Later dictionaries overwrite earlier ones. If you're looking for a fresh merged dictionary instead, check out `Dict.concatMany`.
249+
250+
## Examples
251+
```rescript
252+
let target = dict{"firstKey": 1}
253+
let result = target->Dict.assignMany([
254+
dict{"someKey": 2},
255+
dict{"someKey": 3, "someKey2": 4},
256+
])
257+
258+
result == dict{"firstKey": 1, "someKey": 3, "someKey2": 4}
259+
(result === target) == true
260+
```
261+
*/
262+
@variadic @val
263+
external assignMany: (dict<'a>, array<dict<'a>>) => dict<'a> = "Object.assign"
264+
265+
/**
266+
`concat(dictionary1, dictionary2)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges `dictionary1` and `dictionary2` into a fresh dictionary, and returns the new dictionary.
267+
268+
Neither input dictionary is mutated. If both dictionaries contain the same key, the value from `dictionary2` overwrites the one from `dictionary1`.
269+
270+
## Examples
271+
```rescript
272+
let dict1 = dict{"firstKey": 1}
273+
let dict2 = dict{"firstKey": 2, "someKey": 3}
274+
275+
let merged = dict1->Dict.concat(dict2)
276+
277+
dict1 == dict{"firstKey": 1}
278+
merged == dict{"firstKey": 2, "someKey": 3}
279+
(merged === dict1) == false
280+
```
281+
*/
282+
@val
283+
external concat: (@as(json`{}`) _, dict<'a>, dict<'a>) => dict<'a> = "Object.assign"
284+
285+
/**
286+
`concatMany(target, sources)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges `target` and each dictionary in `sources` into a fresh dictionary, and returns the new dictionary.
287+
288+
Neither `target` nor any dictionary in `sources` is mutated. Later dictionaries overwrite earlier ones when they contain the same key.
289+
290+
## Examples
291+
```rescript
292+
let target = dict{"firstKey": 1}
293+
let merged = target->Dict.concatMany([
294+
dict{"someKey": 2},
295+
dict{"someKey": 3, "someKey2": 4},
296+
])
297+
298+
target == dict{"firstKey": 1}
299+
merged == dict{"firstKey": 1, "someKey": 3, "someKey2": 4}
300+
(merged === target) == false
301+
```
302+
*/
303+
@variadic @val
304+
external concatMany: (@as(json`{}`) _, dict<'a>, array<dict<'a>>) => dict<'a> = "Object.assign"
305+
306+
/**
307+
`concatAll(dictionaries)` [shallowly](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) merges all dictionaries in `dictionaries` into a fresh dictionary, and returns the new dictionary.
308+
309+
None of the input dictionaries are mutated. Later dictionaries overwrite earlier ones when they contain the same key. If `dictionaries` is empty, an empty dictionary is returned.
310+
311+
## Examples
312+
```rescript
313+
let dict1 = dict{"firstKey": 1}
314+
let dict2 = dict{"someKey": 2}
315+
let dict3 = dict{"someKey": 3, "someKey2": 4}
316+
317+
let merged = Dict.concatAll([dict1, dict2, dict3])
318+
319+
dict1 == dict{"firstKey": 1}
320+
merged == dict{"firstKey": 1, "someKey": 3, "someKey2": 4}
321+
(merged === dict1) == false
322+
```
323+
*/
324+
@variadic @val
325+
external concatAll: (@as(json`{}`) _, array<dict<'a>>) => dict<'a> = "Object.assign"
326+
245327
/**
246328
`copy(dictionary)` [shallowly copies](https://developer.mozilla.org/en-US/docs/Glossary/Shallow_copy) the provided dictionary to a new dictionary.
247329

packages/@rescript/runtime/lib/es6/Stdlib_Array.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ function compare(a, b, cmp) {
7171
}
7272
}
7373

74+
function concatAll(arrays) {
75+
return [].concat(...arrays);
76+
}
77+
7478
function indexOfOpt(arr, item) {
7579
let index = arr.indexOf(item);
7680
if (index !== -1) {
@@ -264,6 +268,7 @@ export {
264268
equal,
265269
compare,
266270
isEmpty,
271+
concatAll,
267272
indexOfOpt,
268273
lastIndexOfOpt,
269274
reduce,

packages/@rescript/runtime/lib/js/Stdlib_Array.cjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ function compare(a, b, cmp) {
7171
}
7272
}
7373

74+
function concatAll(arrays) {
75+
return [].concat(...arrays);
76+
}
77+
7478
function indexOfOpt(arr, item) {
7579
let index = arr.indexOf(item);
7680
if (index !== -1) {
@@ -263,6 +267,7 @@ exports.fromInitializer = fromInitializer;
263267
exports.equal = equal;
264268
exports.compare = compare;
265269
exports.isEmpty = isEmpty;
270+
exports.concatAll = concatAll;
266271
exports.indexOfOpt = indexOfOpt;
267272
exports.lastIndexOfOpt = lastIndexOfOpt;
268273
exports.reduce = reduce;

tests/analysis_tests/tests/src/expected/Completion.res.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,12 @@ Path Array.
490490
"tags": [],
491491
"detail": "(array<'a>, array<'a>, ('a, 'a) => bool) => bool",
492492
"documentation": {"kind": "markdown", "value": "\n`equal(left, right, predicate)` checks if the two arrays contain the same elements according to the equality `predicate`.\n\n## Examples\n\n```rescript\nArray.equal([1, 2, 3], [1, 2, 3], Int.equal) == true\nArray.equal([1, 2, 3], [1, 3, 2], Int.equal) == false\n```\n"}
493+
}, {
494+
"label": "concatAll",
495+
"kind": 12,
496+
"tags": [],
497+
"detail": "array<array<'a>> => array<'a>",
498+
"documentation": {"kind": "markdown", "value": "\n`concatAll(arrays)` concatenates all arrays in `arrays`, creating a new array.\n\nSee [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) on MDN.\n\n## Examples\n```rescript\nlet arrays = [[\"hi\", \"hello\"], [\"yay\"], [\"wehoo\"]]\n\nlet result = Array.concatAll(arrays)\n\narrays == [[\"hi\", \"hello\"], [\"yay\"], [\"wehoo\"]]\nresult == [\"hi\", \"hello\", \"yay\", \"wehoo\"]\n```\n"}
493499
}, {
494500
"label": "joinUnsafe",
495501
"kind": 12,

tests/tests/src/stdlib/Stdlib_ArrayTests.mjs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -443,10 +443,70 @@ Test.run([
443443
"c"
444444
]);
445445

446+
let arrays = [
447+
[
448+
1,
449+
2
450+
],
451+
[3],
452+
[
453+
4,
454+
5
455+
]
456+
];
457+
458+
let result = Stdlib_Array.concatAll(arrays);
459+
460+
Test.run([
461+
[
462+
"Stdlib_ArrayTests.res",
463+
121,
464+
22,
465+
53
466+
],
467+
"concatAll concatenates arrays"
468+
], result, eq, [
469+
1,
470+
2,
471+
3,
472+
4,
473+
5
474+
]);
475+
476+
Test.run([
477+
[
478+
"Stdlib_ArrayTests.res",
479+
123,
480+
15,
481+
57
482+
],
483+
"concatAll leaves source arrays unchanged"
484+
], arrays, eq, [
485+
[
486+
1,
487+
2
488+
],
489+
[3],
490+
[
491+
4,
492+
5
493+
]
494+
]);
495+
496+
Test.run([
497+
[
498+
"Stdlib_ArrayTests.res",
499+
130,
500+
20,
501+
39
502+
],
503+
"concatAll - empty"
504+
], Stdlib_Array.concatAll([]), eq, []);
505+
446506
Test.run([
447507
[
448508
"Stdlib_ArrayTests.res",
449-
118,
509+
133,
450510
13,
451511
31
452512
],
@@ -465,7 +525,7 @@ Test.run([
465525
Test.run([
466526
[
467527
"Stdlib_ArrayTests.res",
468-
125,
528+
140,
469529
13,
470530
31
471531
],
@@ -479,7 +539,7 @@ Test.run([
479539
Test.run([
480540
[
481541
"Stdlib_ArrayTests.res",
482-
132,
542+
147,
483543
13,
484544
29
485545
],
@@ -507,7 +567,7 @@ Test.run([
507567
Test.run([
508568
[
509569
"Stdlib_ArrayTests.res",
510-
139,
570+
154,
511571
13,
512572
29
513573
],
@@ -524,7 +584,7 @@ Test.run([
524584
Test.run([
525585
[
526586
"Stdlib_ArrayTests.res",
527-
145,
587+
160,
528588
20,
529589
39
530590
],
@@ -538,7 +598,7 @@ Test.run([
538598
Test.run([
539599
[
540600
"Stdlib_ArrayTests.res",
541-
146,
601+
161,
542602
20,
543603
34
544604
],
@@ -552,7 +612,7 @@ array.splice(1, 0, "foo");
552612
Test.run([
553613
[
554614
"Stdlib_ArrayTests.res",
555-
151,
615+
166,
556616
22,
557617
49
558618
],
@@ -567,7 +627,7 @@ let array$1 = [
567627
Test.run([
568628
[
569629
"Stdlib_ArrayTests.res",
570-
157,
630+
172,
571631
15,
572632
43
573633
],

tests/tests/src/stdlib/Stdlib_ArrayTests.res

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,21 @@ Test.run(
114114
["a", "b", "c"],
115115
)
116116

117+
{
118+
let arrays = [[1, 2], [3], [4, 5]]
119+
let result = Array.concatAll(arrays)
120+
121+
Test.run(__POS_OF__("concatAll concatenates arrays"), result, eq, [1, 2, 3, 4, 5])
122+
Test.run(
123+
__POS_OF__("concatAll leaves source arrays unchanged"),
124+
arrays,
125+
eq,
126+
[[1, 2], [3], [4, 5]],
127+
)
128+
}
129+
130+
Test.run(__POS_OF__("concatAll - empty"), Array.concatAll([]), eq, [])
131+
117132
Test.run(
118133
__POS_OF__("Map.fromIterable"),
119134
Map.fromIterable([("one", 1), ("two", 2)]->Array.asIterable)->Map.size,

0 commit comments

Comments
 (0)