nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1/**
2 General list operations.
3*/
4{ lib }:
5let
6 inherit (lib.strings) toInt;
7 inherit (lib.trivial)
8 compare
9 min
10 id
11 warn
12 ;
13 inherit (lib.attrsets) mapAttrs attrNames attrValues;
14 inherit (lib) max;
15in
16rec {
17
18 inherit (builtins)
19 head
20 tail
21 length
22 isList
23 elemAt
24 concatLists
25 filter
26 elem
27 genList
28 map
29 ;
30
31 /**
32 Create a list consisting of a single element. `singleton x` is
33 sometimes more convenient with respect to indentation than `[x]`
34 when x spans multiple lines.
35
36 # Inputs
37
38 `x`
39
40 : 1\. Function argument
41
42 # Type
43
44 ```
45 singleton :: a -> [a]
46 ```
47
48 # Examples
49 :::{.example}
50 ## `lib.lists.singleton` usage example
51
52 ```nix
53 singleton "foo"
54 => [ "foo" ]
55 ```
56
57 :::
58 */
59 singleton = x: [ x ];
60
61 /**
62 Apply the function to each element in the list.
63 Same as `map`, but arguments flipped.
64
65 # Inputs
66
67 `xs`
68
69 : 1\. Function argument
70
71 `f`
72
73 : 2\. Function argument
74
75 # Type
76
77 ```
78 forEach :: [a] -> (a -> b) -> [b]
79 ```
80
81 # Examples
82 :::{.example}
83 ## `lib.lists.forEach` usage example
84
85 ```nix
86 forEach [ 1 2 ] (x:
87 toString x
88 )
89 => [ "1" "2" ]
90 ```
91
92 :::
93 */
94 forEach = xs: f: map f xs;
95
96 /**
97 “right fold” a binary function `op` between successive elements of
98 `list` with `nul` as the starting value, i.e.,
99 `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
100
101 # Inputs
102
103 `op`
104
105 : 1\. Function argument
106
107 `nul`
108
109 : 2\. Function argument
110
111 `list`
112
113 : 3\. Function argument
114
115 # Type
116
117 ```
118 foldr :: (a -> b -> b) -> b -> [a] -> b
119 ```
120
121 # Examples
122 :::{.example}
123 ## `lib.lists.foldr` usage example
124
125 ```nix
126 concat = foldr (a: b: a + b) "z"
127 concat [ "a" "b" "c" ]
128 => "abcz"
129 # different types
130 strange = foldr (int: str: toString (int + 1) + str) "a"
131 strange [ 1 2 3 4 ]
132 => "2345a"
133 ```
134
135 :::
136 */
137 foldr =
138 op: nul: list:
139 let
140 len = length list;
141 fold' = n: if n == len then nul else op (elemAt list n) (fold' (n + 1));
142 in
143 fold' 0;
144
145 /**
146 `fold` is an alias of `foldr` for historic reasons.
147
148 ::: {.warning}
149 This function will be removed in 26.05.
150 :::
151 */
152 fold = warn "fold has been deprecated, use foldr instead" foldr;
153
154 /**
155 “left fold”, like `foldr`, but from the left:
156
157 `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
158
159 # Inputs
160
161 `op`
162
163 : 1\. Function argument
164
165 `nul`
166
167 : 2\. Function argument
168
169 `list`
170
171 : 3\. Function argument
172
173 # Type
174
175 ```
176 foldl :: (b -> a -> b) -> b -> [a] -> b
177 ```
178
179 # Examples
180 :::{.example}
181 ## `lib.lists.foldl` usage example
182
183 ```nix
184 lconcat = foldl (a: b: a + b) "z"
185 lconcat [ "a" "b" "c" ]
186 => "zabc"
187 # different types
188 lstrange = foldl (str: int: str + toString (int + 1)) "a"
189 lstrange [ 1 2 3 4 ]
190 => "a2345"
191 ```
192
193 :::
194 */
195 foldl =
196 op: nul: list:
197 let
198 foldl' = n: if n == -1 then nul else op (foldl' (n - 1)) (elemAt list n);
199 in
200 foldl' (length list - 1);
201
202 /**
203 Reduce a list by applying a binary operator from left to right,
204 starting with an initial accumulator.
205
206 Before each application of the operator, the accumulator value is evaluated.
207 This behavior makes this function stricter than [`foldl`](#function-library-lib.lists.foldl).
208
209 Unlike [`builtins.foldl'`](https://nixos.org/manual/nix/unstable/language/builtins.html#builtins-foldl'),
210 the initial accumulator argument is evaluated before the first iteration.
211
212 A call like
213
214 ```nix
215 foldl' op acc₀ [ x₀ x₁ x₂ ... xₙ₋₁ xₙ ]
216 ```
217
218 is (denotationally) equivalent to the following,
219 but with the added benefit that `foldl'` itself will never overflow the stack.
220
221 ```nix
222 let
223 acc₁ = builtins.seq acc₀ (op acc₀ x₀ );
224 acc₂ = builtins.seq acc₁ (op acc₁ x₁ );
225 acc₃ = builtins.seq acc₂ (op acc₂ x₂ );
226 ...
227 accₙ = builtins.seq accₙ₋₁ (op accₙ₋₁ xₙ₋₁);
228 accₙ₊₁ = builtins.seq accₙ (op accₙ xₙ );
229 in
230 accₙ₊₁
231
232 # Or ignoring builtins.seq
233 op (op (... (op (op (op acc₀ x₀) x₁) x₂) ...) xₙ₋₁) xₙ
234 ```
235
236 # Inputs
237
238 `op`
239
240 : The binary operation to run, where the two arguments are:
241
242 1. `acc`: The current accumulator value: Either the initial one for the first iteration, or the result of the previous iteration
243 2. `x`: The corresponding list element for this iteration
244
245 `acc`
246
247 : The initial accumulator value.
248
249 The accumulator value is evaluated in any case before the first iteration starts.
250
251 To avoid evaluation even before the `list` argument is given an eta expansion can be used:
252
253 ```nix
254 list: lib.foldl' op acc list
255 ```
256
257 `list`
258
259 : The list to fold
260
261 # Type
262
263 ```
264 foldl' :: (a -> b -> a) -> a -> [b] -> a
265 ```
266
267 # Examples
268 :::{.example}
269 ## `lib.lists.foldl'` usage example
270
271 ```nix
272 foldl' (acc: x: acc + x) 0 [1 2 3]
273 => 6
274 ```
275
276 :::
277 */
278 foldl' =
279 op: acc:
280 # The builtin `foldl'` is a bit lazier than one might expect.
281 # See https://github.com/NixOS/nix/pull/7158.
282 # In particular, the initial accumulator value is not forced before the first iteration starts.
283 builtins.seq acc (builtins.foldl' op acc);
284
285 /**
286 Map with index starting from 0
287
288 # Inputs
289
290 `f`
291
292 : 1\. Function argument
293
294 `list`
295
296 : 2\. Function argument
297
298 # Type
299
300 ```
301 imap0 :: (Int -> a -> b) -> [a] -> [b]
302 ```
303
304 # Examples
305 :::{.example}
306 ## `lib.lists.imap0` usage example
307
308 ```nix
309 imap0 (i: v: "${v}-${toString i}") ["a" "b"]
310 => [ "a-0" "b-1" ]
311 ```
312
313 :::
314 */
315 imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
316
317 /**
318 Map with index starting from 1
319
320 # Inputs
321
322 `f`
323
324 : 1\. Function argument
325
326 `list`
327
328 : 2\. Function argument
329
330 # Type
331
332 ```
333 imap1 :: (Int -> a -> b) -> [a] -> [b]
334 ```
335
336 # Examples
337 :::{.example}
338 ## `lib.lists.imap1` usage example
339
340 ```nix
341 imap1 (i: v: "${v}-${toString i}") ["a" "b"]
342 => [ "a-1" "b-2" ]
343 ```
344
345 :::
346 */
347 imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
348
349 /**
350 Filter a list for elements that satisfy a predicate function.
351 The predicate function is called with both the index and value for each element.
352 It must return `true`/`false` to include/exclude a given element in the result.
353 This function is strict in the result of the predicate function for each element.
354 This function has O(n) complexity.
355
356 Also see [`builtins.filter`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filter) (available as `lib.lists.filter`),
357 which can be used instead when the index isn't needed.
358
359 # Inputs
360
361 `ipred`
362
363 : The predicate function, it takes two arguments:
364 - 1. (int): the index of the element.
365 - 2. (a): the value of the element.
366
367 It must return `true`/`false` to include/exclude a given element from the result.
368
369 `list`
370
371 : The list to filter using the predicate.
372
373 # Type
374 ```
375 ifilter0 :: (Int -> a -> Bool) -> [a] -> [a]
376 ```
377
378 # Examples
379 :::{.example}
380 ## `lib.lists.ifilter0` usage example
381
382 ```nix
383 ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ]
384 => [ 1 3 ]
385 ```
386 :::
387 */
388 ifilter0 =
389 ipred: input:
390 map (idx: elemAt input idx) (
391 filter (idx: ipred idx (elemAt input idx)) (genList (x: x) (length input))
392 );
393
394 /**
395 Map and concatenate the result.
396
397 # Type
398
399 ```
400 concatMap :: (a -> [b]) -> [a] -> [b]
401 ```
402
403 # Examples
404 :::{.example}
405 ## `lib.lists.concatMap` usage example
406
407 ```nix
408 concatMap (x: [x] ++ ["z"]) ["a" "b"]
409 => [ "a" "z" "b" "z" ]
410 ```
411
412 :::
413 */
414 concatMap = builtins.concatMap;
415
416 /**
417 Flatten the argument into a single list; that is, nested lists are
418 spliced into the top-level lists.
419
420 # Inputs
421
422 `x`
423
424 : 1\. Function argument
425
426 # Type
427
428 ```
429 flatten :: [a | [a | [a | ...]]] -> [a]
430 ```
431
432 # Examples
433 :::{.example}
434 ## `lib.lists.flatten` usage example
435
436 ```nix
437 flatten [1 [2 [3] 4] 5]
438 => [1 2 3 4 5]
439 flatten 1
440 => [1]
441 ```
442
443 :::
444 */
445 flatten = x: if isList x then concatMap (y: flatten y) x else [ x ];
446
447 /**
448 Remove elements equal to `e` from a list. Useful for `buildInputs`.
449
450 # Inputs
451
452 `e`
453
454 : Element to remove from `list`
455
456 `list`
457
458 : The list
459
460 # Type
461
462 ```
463 remove :: a -> [a] -> [a]
464 ```
465
466 # Examples
467 :::{.example}
468 ## `lib.lists.remove` usage example
469
470 ```nix
471 remove 3 [ 1 3 4 3 ]
472 => [ 1 4 ]
473 ```
474
475 :::
476 */
477 remove = e: filter (x: x != e);
478
479 /**
480 Find the sole element in the list matching the specified
481 predicate.
482
483 Returns `default` if no such element exists, or
484 `multiple` if there are multiple matching elements.
485
486 # Inputs
487
488 `pred`
489
490 : Predicate
491
492 `default`
493
494 : Default value to return if element was not found.
495
496 `multiple`
497
498 : Default value to return if more than one element was found
499
500 `list`
501
502 : Input list
503
504 # Type
505
506 ```
507 findSingle :: (a -> Bool) -> a -> a -> [a] -> a
508 ```
509
510 # Examples
511 :::{.example}
512 ## `lib.lists.findSingle` usage example
513
514 ```nix
515 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
516 => "multiple"
517 findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
518 => 3
519 findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
520 => "none"
521 ```
522
523 :::
524 */
525 findSingle =
526 pred: default: multiple: list:
527 let
528 found = filter pred list;
529 len = length found;
530 in
531 if len == 0 then
532 default
533 else if len != 1 then
534 multiple
535 else
536 head found;
537
538 /**
539 Find the first index in the list matching the specified
540 predicate or return `default` if no such element exists.
541
542 # Inputs
543
544 `pred`
545
546 : Predicate
547
548 `default`
549
550 : Default value to return
551
552 `list`
553
554 : Input list
555
556 # Type
557
558 ```
559 findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b)
560 ```
561
562 # Examples
563 :::{.example}
564 ## `lib.lists.findFirstIndex` usage example
565
566 ```nix
567 findFirstIndex (x: x > 3) null [ 0 6 4 ]
568 => 1
569 findFirstIndex (x: x > 9) null [ 0 6 4 ]
570 => null
571 ```
572
573 :::
574 */
575 findFirstIndex =
576 pred: default: list:
577 let
578 # A naive recursive implementation would be much simpler, but
579 # would also overflow the evaluator stack. We use `foldl'` as a workaround
580 # because it reuses the same stack space, evaluating the function for one
581 # element after another. We can't return early, so this means that we
582 # sacrifice early cutoff, but that appears to be an acceptable cost. A
583 # clever scheme with "exponential search" is possible, but appears over-
584 # engineered for now. See https://github.com/NixOS/nixpkgs/pull/235267
585
586 # Invariant:
587 # - if index < 0 then el == elemAt list (- index - 1) and all elements before el didn't satisfy pred
588 # - if index >= 0 then pred (elemAt list index) and all elements before (elemAt list index) didn't satisfy pred
589 #
590 # We start with index -1 and the 0'th element of the list, which satisfies the invariant
591 resultIndex = foldl' (
592 index: el:
593 if index < 0 then
594 # No match yet before the current index, we need to check the element
595 if pred el then
596 # We have a match! Turn it into the actual index to prevent future iterations from modifying it
597 -index - 1
598 else
599 # Still no match, update the index to the next element (we're counting down, so minus one)
600 index - 1
601 else
602 # There's already a match, propagate the index without evaluating anything
603 index
604 ) (-1) list;
605 in
606 if resultIndex < 0 then default else resultIndex;
607
608 /**
609 Find the first element in the list matching the specified
610 predicate or return `default` if no such element exists.
611
612 # Inputs
613
614 `pred`
615
616 : Predicate
617
618 `default`
619
620 : Default value to return
621
622 `list`
623
624 : Input list
625
626 # Type
627
628 ```
629 findFirst :: (a -> Bool) -> a -> [a] -> a
630 ```
631
632 # Examples
633 :::{.example}
634 ## `lib.lists.findFirst` usage example
635
636 ```nix
637 findFirst (x: x > 3) 7 [ 1 6 4 ]
638 => 6
639 findFirst (x: x > 9) 7 [ 1 6 4 ]
640 => 7
641 ```
642
643 :::
644 */
645 findFirst =
646 pred: default: list:
647 let
648 index = findFirstIndex pred null list;
649 in
650 if index == null then default else elemAt list index;
651
652 /**
653 Returns true if function `pred` returns true for at least one
654 element of `list`.
655
656 # Inputs
657
658 `pred`
659
660 : Predicate
661
662 `list`
663
664 : Input list
665
666 # Type
667
668 ```
669 any :: (a -> Bool) -> [a] -> Bool
670 ```
671
672 # Examples
673 :::{.example}
674 ## `lib.lists.any` usage example
675
676 ```nix
677 any isString [ 1 "a" { } ]
678 => true
679 any isString [ 1 { } ]
680 => false
681 ```
682
683 :::
684 */
685 any = builtins.any;
686
687 /**
688 Returns true if function `pred` returns true for all elements of
689 `list`.
690
691 # Inputs
692
693 `pred`
694
695 : Predicate
696
697 `list`
698
699 : Input list
700
701 # Type
702
703 ```
704 all :: (a -> Bool) -> [a] -> Bool
705 ```
706
707 # Examples
708 :::{.example}
709 ## `lib.lists.all` usage example
710
711 ```nix
712 all (x: x < 3) [ 1 2 ]
713 => true
714 all (x: x < 3) [ 1 2 3 ]
715 => false
716 ```
717
718 :::
719 */
720 all = builtins.all;
721
722 /**
723 Count how many elements of `list` match the supplied predicate
724 function.
725
726 # Inputs
727
728 `pred`
729
730 : Predicate
731
732 # Type
733
734 ```
735 count :: (a -> Bool) -> [a] -> Int
736 ```
737
738 # Examples
739 :::{.example}
740 ## `lib.lists.count` usage example
741
742 ```nix
743 count (x: x == 3) [ 3 2 3 4 6 ]
744 => 2
745 ```
746
747 :::
748 */
749 count = pred: foldl' (c: x: if pred x then c + 1 else c) 0;
750
751 /**
752 Return a singleton list or an empty list, depending on a boolean
753 value. Useful when building lists with optional elements
754 (e.g. `++ optional (system == "i686-linux") firefox`).
755
756 # Inputs
757
758 `cond`
759
760 : 1\. Function argument
761
762 `elem`
763
764 : 2\. Function argument
765
766 # Type
767
768 ```
769 optional :: Bool -> a -> [a]
770 ```
771
772 # Examples
773 :::{.example}
774 ## `lib.lists.optional` usage example
775
776 ```nix
777 optional true "foo"
778 => [ "foo" ]
779 optional false "foo"
780 => [ ]
781 ```
782
783 :::
784 */
785 optional = cond: elem: if cond then [ elem ] else [ ];
786
787 /**
788 Returns a list or an empty list, depending on a boolean value.
789
790 # Inputs
791
792 `cond`
793
794 : Condition
795
796 `elems`
797
798 : List to return if condition is true
799
800 # Type
801
802 ```
803 optionals :: Bool -> [a] -> [a]
804 ```
805
806 # Examples
807 :::{.example}
808 ## `lib.lists.optionals` usage example
809
810 ```nix
811 optionals true [ 2 3 ]
812 => [ 2 3 ]
813 optionals false [ 2 3 ]
814 => [ ]
815 ```
816
817 :::
818 */
819 optionals = cond: elems: if cond then elems else [ ];
820
821 /**
822 If argument is a list, return it; else, wrap it in a singleton
823 list. If you're using this, you should almost certainly
824 reconsider if there isn't a more "well-typed" approach.
825
826 # Inputs
827
828 `x`
829
830 : 1\. Function argument
831
832 # Type
833
834 ```
835 toList :: (a | [a]) -> [a]
836 ```
837
838 # Examples
839 :::{.example}
840 ## `lib.lists.toList` usage example
841
842 ```nix
843 toList [ 1 2 ]
844 => [ 1 2 ]
845 toList "hi"
846 => [ "hi" ]
847 ```
848
849 :::
850 */
851 toList = x: if isList x then x else [ x ];
852
853 /**
854 Returns a list of integers from `first` up to and including `last`.
855
856 # Inputs
857
858 `first`
859
860 : First integer in the range
861
862 `last`
863
864 : Last integer in the range
865
866 # Type
867
868 ```
869 range :: Int -> Int -> [Int]
870 ```
871
872 # Examples
873 :::{.example}
874 ## `lib.lists.range` usage example
875
876 ```nix
877 range 2 4
878 => [ 2 3 4 ]
879 range 3 2
880 => [ ]
881 ```
882
883 :::
884 */
885 range = first: last: if first > last then [ ] else genList (n: first + n) (last - first + 1);
886
887 /**
888 Returns a list with `n` copies of an element.
889
890 # Inputs
891
892 `n`
893
894 : 1\. Function argument
895
896 `elem`
897
898 : 2\. Function argument
899
900 # Type
901
902 ```
903 replicate :: Int -> a -> [a]
904 ```
905
906 # Examples
907 :::{.example}
908 ## `lib.lists.replicate` usage example
909
910 ```nix
911 replicate 3 "a"
912 => [ "a" "a" "a" ]
913 replicate 2 true
914 => [ true true ]
915 ```
916
917 :::
918 */
919 replicate = n: elem: genList (_: elem) n;
920
921 /**
922 Splits the elements of a list in two lists, `right` and
923 `wrong`, depending on the evaluation of a predicate.
924
925 # Inputs
926
927 `pred`
928
929 : Predicate
930
931 `list`
932
933 : Input list
934
935 # Type
936
937 ```
938 partition :: (a -> Bool) -> [a] -> { right :: [a]; wrong :: [a]; }
939 ```
940
941 # Examples
942 :::{.example}
943 ## `lib.lists.partition` usage example
944
945 ```nix
946 partition (x: x > 2) [ 5 1 2 3 4 ]
947 => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
948 ```
949
950 :::
951 */
952 partition = builtins.partition;
953
954 /**
955 Splits the elements of a list into many lists, using the return value of a predicate.
956 Predicate should return a string which becomes keys of attrset `groupBy` returns.
957 `groupBy'` allows to customise the combining function and initial value
958
959 # Inputs
960
961 `op`
962
963 : 1\. Function argument
964
965 `nul`
966
967 : 2\. Function argument
968
969 `pred`
970
971 : 3\. Function argument
972
973 `lst`
974
975 : 4\. Function argument
976
977 # Type
978
979 ```
980 groupBy' :: (a -> b -> a) -> a -> (b -> String) -> [b] -> { [String] :: a }
981 ```
982
983 # Examples
984 :::{.example}
985 ## `lib.lists.groupBy'` usage example
986
987 ```nix
988 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
989 => { true = [ 5 3 4 ]; false = [ 1 2 ]; }
990 groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";}
991 {name = "xfce"; script = "xfce4-session &";}
992 {name = "icewm"; script = "icewmbg &";}
993 {name = "mate"; script = "gnome-session &";}
994 ]
995 => { icewm = [ { name = "icewm"; script = "icewm &"; }
996 { name = "icewm"; script = "icewmbg &"; } ];
997 mate = [ { name = "mate"; script = "gnome-session &"; } ];
998 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
999 }
1000
1001 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
1002 => { true = 12; false = 3; }
1003 ```
1004
1005 :::
1006 */
1007 groupBy' =
1008 op: nul: pred: lst:
1009 mapAttrs (name: foldl op nul) (groupBy pred lst);
1010
1011 groupBy =
1012 builtins.groupBy or (
1013 pred:
1014 foldl' (
1015 r: e:
1016 let
1017 key = pred e;
1018 in
1019 r // { ${key} = (r.${key} or [ ]) ++ [ e ]; }
1020 ) { }
1021 );
1022
1023 /**
1024 Merges two lists of the same size together. If the sizes aren't the same
1025 the merging stops at the shortest. How both lists are merged is defined
1026 by the first argument.
1027
1028 # Inputs
1029
1030 `f`
1031
1032 : Function to zip elements of both lists
1033
1034 `fst`
1035
1036 : First list
1037
1038 `snd`
1039
1040 : Second list
1041
1042 # Type
1043
1044 ```
1045 zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
1046 ```
1047
1048 # Examples
1049 :::{.example}
1050 ## `lib.lists.zipListsWith` usage example
1051
1052 ```nix
1053 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
1054 => ["he" "lo"]
1055 ```
1056
1057 :::
1058 */
1059 zipListsWith =
1060 f: fst: snd:
1061 genList (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
1062
1063 /**
1064 Merges two lists of the same size together. If the sizes aren't the same
1065 the merging stops at the shortest.
1066
1067 # Inputs
1068
1069 `fst`
1070
1071 : First list
1072
1073 `snd`
1074
1075 : Second list
1076
1077 # Type
1078
1079 ```
1080 zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }]
1081 ```
1082
1083 # Examples
1084 :::{.example}
1085 ## `lib.lists.zipLists` usage example
1086
1087 ```nix
1088 zipLists [ 1 2 ] [ "a" "b" ]
1089 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
1090 ```
1091
1092 :::
1093 */
1094 zipLists = zipListsWith (fst: snd: { inherit fst snd; });
1095
1096 /**
1097 Reverse the order of the elements of a list.
1098
1099 # Inputs
1100
1101 `xs`
1102
1103 : 1\. Function argument
1104
1105 # Type
1106
1107 ```
1108 reverseList :: [a] -> [a]
1109 ```
1110
1111 # Examples
1112 :::{.example}
1113 ## `lib.lists.reverseList` usage example
1114
1115 ```nix
1116 reverseList [ "b" "o" "j" ]
1117 => [ "j" "o" "b" ]
1118 ```
1119
1120 :::
1121 */
1122 reverseList =
1123 xs:
1124 let
1125 l = length xs;
1126 in
1127 genList (n: elemAt xs (l - n - 1)) l;
1128
1129 /**
1130 Depth-First Search (DFS) for lists `list != []`.
1131
1132 `before a b == true` means that `b` depends on `a` (there's an
1133 edge from `b` to `a`).
1134
1135 # Inputs
1136
1137 `stopOnCycles`
1138
1139 : 1\. Function argument
1140
1141 `before`
1142
1143 : 2\. Function argument
1144
1145 `list`
1146
1147 : 3\. Function argument
1148
1149 # Type
1150
1151 ```
1152 listDfs :: Bool -> (a -> a -> Bool) -> [a] -> ({ minimal :: a; visited :: [a]; rest :: [a]; } | { cycle :: a; loops :: [a]; visited :: [a]; rest :: [a]; })
1153 ```
1154
1155 # Examples
1156 :::{.example}
1157 ## `lib.lists.listDfs` usage example
1158
1159 ```nix
1160 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
1161 == { minimal = "/"; # minimal element
1162 visited = [ "/home/user" ]; # seen elements (in reverse order)
1163 rest = [ "/home" "other" ]; # everything else
1164 }
1165
1166 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1167 == { cycle = "/"; # cycle encountered at this element
1168 loops = [ "/" ]; # and continues to these elements
1169 visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order)
1170 rest = [ "/home" "other" ]; # everything else
1171 ```
1172
1173 :::
1174 */
1175 listDfs =
1176 stopOnCycles: before: list:
1177 let
1178 dfs' =
1179 us: visited: rest:
1180 let
1181 c = filter (x: before x us) visited;
1182 b = partition (x: before x us) rest;
1183 in
1184 if stopOnCycles && (length c > 0) then
1185 {
1186 cycle = us;
1187 loops = c;
1188 inherit visited rest;
1189 }
1190 else if length b.right == 0 then
1191 # nothing is before us
1192 {
1193 minimal = us;
1194 inherit visited rest;
1195 }
1196 else
1197 # grab the first one before us and continue
1198 dfs' (head b.right) ([ us ] ++ visited) (tail b.right ++ b.wrong);
1199 in
1200 dfs' (head list) [ ] (tail list);
1201
1202 /**
1203 Sort a list based on a partial ordering using DFS. This
1204 implementation is O(N^2), if your ordering is linear, use `sort`
1205 instead.
1206
1207 `before a b == true` means that `b` should be after `a`
1208 in the result.
1209
1210 # Inputs
1211
1212 `before`
1213
1214 : 1\. Function argument
1215
1216 `list`
1217
1218 : 2\. Function argument
1219
1220 # Type
1221
1222 ```
1223 toposort :: (a -> a -> Bool) -> [a] -> ({ result :: [a]; } | { cycle :: [a]; loops :: [a]; })
1224 ```
1225
1226 # Examples
1227 :::{.example}
1228 ## `lib.lists.toposort` usage example
1229
1230 ```nix
1231 toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
1232 == { result = [ "/" "/home" "/home/user" "other" ]; }
1233
1234 toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1235 == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle
1236 loops = [ "/" ]; } # loops back to these elements
1237
1238 toposort hasPrefix [ "other" "/home/user" "/home" "/" ]
1239 == { result = [ "other" "/" "/home" "/home/user" ]; }
1240
1241 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
1242 ```
1243
1244 :::
1245 */
1246 toposort =
1247 before: list:
1248 let
1249 dfsthis = listDfs true before list;
1250 toporest = toposort before (dfsthis.visited ++ dfsthis.rest);
1251 in
1252 if length list < 2 then
1253 # finish
1254 { result = list; }
1255 else if dfsthis ? cycle then
1256 # there's a cycle, starting from the current vertex, return it
1257 {
1258 cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited);
1259 inherit (dfsthis) loops;
1260 }
1261 else if toporest ? cycle then
1262 # there's a cycle somewhere else in the graph, return it
1263 toporest
1264 # Slow, but short. Can be made a bit faster with an explicit stack.
1265 else
1266 # there are no cycles
1267 { result = [ dfsthis.minimal ] ++ toporest.result; };
1268
1269 /**
1270 Sort a list based on a comparator function which compares two
1271 elements and returns true if the first argument is strictly below
1272 the second argument. The returned list is sorted in an increasing
1273 order. The implementation does a quick-sort.
1274
1275 See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the
1276 default comparison on a function-derived property, and may be more efficient.
1277
1278 # Inputs
1279
1280 `comparator`
1281
1282 : 1\. Function argument
1283
1284 `list`
1285
1286 : 2\. Function argument
1287
1288 # Type
1289
1290 ```
1291 sort :: (a -> a -> Bool) -> [a] -> [a]
1292 ```
1293
1294 # Examples
1295 :::{.example}
1296 ## `lib.lists.sort` usage example
1297
1298 ```nix
1299 sort (p: q: p < q) [ 5 3 7 ]
1300 => [ 3 5 7 ]
1301 ```
1302
1303 :::
1304 */
1305 sort = builtins.sort;
1306
1307 /**
1308 Sort a list based on the default comparison of a derived property `b`.
1309
1310 The items are returned in `b`-increasing order.
1311
1312 **Performance**:
1313
1314 The passed function `f` is only evaluated once per item,
1315 unlike an unprepared [`sort`](#function-library-lib.lists.sort) using
1316 `f p < f q`.
1317
1318 **Laws**:
1319 ```nix
1320 sortOn f == sort (p: q: f p < f q)
1321 ```
1322
1323 # Inputs
1324
1325 `f`
1326
1327 : 1\. Function argument
1328
1329 `list`
1330
1331 : 2\. Function argument
1332
1333 # Type
1334
1335 ```
1336 sortOn :: (a -> b) -> [a] -> [a], for comparable b
1337 ```
1338
1339 # Examples
1340 :::{.example}
1341 ## `lib.lists.sortOn` usage example
1342
1343 ```nix
1344 sortOn stringLength [ "aa" "b" "cccc" ]
1345 => [ "b" "aa" "cccc" ]
1346 ```
1347
1348 :::
1349 */
1350 sortOn =
1351 f: list:
1352 let
1353 # Heterogenous list as pair may be ugly, but requires minimal allocations.
1354 pairs = map (x: [
1355 (f x)
1356 x
1357 ]) list;
1358 in
1359 map (x: builtins.elemAt x 1) (
1360 sort
1361 # Compare the first element of the pairs
1362 # Do not factor out the `<`, to avoid calls in hot code; duplicate instead.
1363 (a: b: head a < head b)
1364 pairs
1365 );
1366
1367 /**
1368 Compare two lists element-by-element with a comparison function `cmp`.
1369
1370 List elements are compared pairwise in order by the provided comparison function `cmp`,
1371 the first non-equal pair of elements determines the result.
1372
1373 :::{.note}
1374 The `<` operator can also be used to compare lists using a boolean condition. (e.g. `[1 2] < [1 3]` is `true`).
1375 See also [language operators](https://nix.dev/manual/nix/stable/language/operators#comparison) for more information.
1376 :::
1377
1378 # Inputs
1379
1380 `cmp`
1381
1382 : The comparison function `a: b: ...` must return:
1383 - `0` if `a` and `b` are equal
1384 - `1` if `a` is greater than `b`
1385 - `-1` if `a` is less than `b`
1386
1387 See [lib.compare](#function-library-lib.trivial.compare) for a an example implementation.
1388
1389 `a`
1390
1391 : The first list
1392
1393 `b`
1394
1395 : The second list
1396
1397 # Type
1398
1399 ```
1400 compareLists :: (a -> a -> Int) -> [a] -> [a] -> Int
1401 ```
1402
1403 # Examples
1404 :::{.example}
1405 ## `lib.lists.compareLists` usage examples
1406
1407 ```nix
1408 compareLists lib.compare [] []
1409 => 0
1410 compareLists lib.compare [] [ "a" ]
1411 => -1
1412 compareLists lib.compare [ "a" ] []
1413 => 1
1414 compareLists lib.compare [ "a" "b" ] [ "a" "c" ]
1415 => -1
1416 ```
1417
1418 :::
1419 */
1420 compareLists =
1421 cmp: a: b:
1422 if a == [ ] then
1423 if b == [ ] then 0 else -1
1424 else if b == [ ] then
1425 1
1426 else
1427 let
1428 rel = cmp (head a) (head b);
1429 in
1430 if rel == 0 then compareLists cmp (tail a) (tail b) else rel;
1431
1432 /**
1433 Sort list using "Natural sorting".
1434 Numeric portions of strings are sorted in numeric order.
1435
1436 # Inputs
1437
1438 `lst`
1439
1440 : 1\. Function argument
1441
1442 # Type
1443
1444 ```
1445 naturalSort :: [String] -> [String]
1446 ```
1447
1448 # Examples
1449 :::{.example}
1450 ## `lib.lists.naturalSort` usage example
1451
1452 ```nix
1453 naturalSort ["disk11" "disk8" "disk100" "disk9"]
1454 => ["disk8" "disk9" "disk11" "disk100"]
1455 naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
1456 => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
1457 naturalSort ["v0.2" "v0.15" "v0.0.9"]
1458 => [ "v0.0.9" "v0.2" "v0.15" ]
1459 ```
1460
1461 :::
1462 */
1463 naturalSort =
1464 lst:
1465 let
1466 vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
1467 prepared = map (x: [
1468 (vectorise x)
1469 x
1470 ]) lst; # remember vectorised version for O(n) regex splits
1471 less = a: b: (compareLists compare (head a) (head b)) < 0;
1472 in
1473 map (x: elemAt x 1) (sort less prepared);
1474
1475 /**
1476 Returns the first (at most) N elements of a list.
1477
1478 # Inputs
1479
1480 `count`
1481
1482 : Number of elements to take
1483
1484 `list`
1485
1486 : Input list
1487
1488 # Type
1489
1490 ```
1491 take :: Int -> [a] -> [a]
1492 ```
1493
1494 # Examples
1495 :::{.example}
1496 ## `lib.lists.take` usage example
1497
1498 ```nix
1499 take 2 [ "a" "b" "c" "d" ]
1500 => [ "a" "b" ]
1501 take 2 [ ]
1502 => [ ]
1503 ```
1504
1505 :::
1506 */
1507 take = count: sublist 0 count;
1508
1509 /**
1510 Returns the last (at most) N elements of a list.
1511
1512 # Inputs
1513
1514 `count`
1515
1516 : Maximum number of elements to pick
1517
1518 `list`
1519
1520 : Input list
1521
1522 # Type
1523
1524 ```
1525 takeEnd :: Int -> [a] -> [a]
1526 ```
1527
1528 # Examples
1529 :::{.example}
1530 ## `lib.lists.takeEnd` usage example
1531
1532 ```nix
1533 takeEnd 2 [ "a" "b" "c" "d" ]
1534 => [ "c" "d" ]
1535 takeEnd 2 [ ]
1536 => [ ]
1537 ```
1538
1539 :::
1540 */
1541 takeEnd = n: xs: drop (max 0 (length xs - n)) xs;
1542
1543 /**
1544 Remove the first (at most) N elements of a list.
1545
1546 # Inputs
1547
1548 `count`
1549
1550 : Number of elements to drop
1551
1552 `list`
1553
1554 : Input list
1555
1556 # Type
1557
1558 ```
1559 drop :: Int -> [a] -> [a]
1560 ```
1561
1562 # Examples
1563 :::{.example}
1564 ## `lib.lists.drop` usage example
1565
1566 ```nix
1567 drop 2 [ "a" "b" "c" "d" ]
1568 => [ "c" "d" ]
1569 drop 2 [ ]
1570 => [ ]
1571 ```
1572
1573 :::
1574 */
1575 drop = count: list: sublist count (length list) list;
1576
1577 /**
1578 Remove the last (at most) N elements of a list.
1579
1580 # Inputs
1581
1582 `count`
1583
1584 : Number of elements to drop
1585
1586 `list`
1587
1588 : Input list
1589
1590 # Type
1591
1592 ```
1593 dropEnd :: Int -> [a] -> [a]
1594 ```
1595
1596 # Examples
1597
1598 :::{.example}
1599 ## `lib.lists.dropEnd` usage example
1600
1601 ```nix
1602 dropEnd 2 [ "a" "b" "c" "d" ]
1603 => [ "a" "b" ]
1604 dropEnd 2 [ ]
1605 => [ ]
1606 ```
1607 :::
1608 */
1609 dropEnd = n: xs: take (max 0 (length xs - n)) xs;
1610
1611 /**
1612 Whether the first list is a prefix of the second list.
1613
1614 # Inputs
1615
1616 `list1`
1617
1618 : 1\. Function argument
1619
1620 `list2`
1621
1622 : 2\. Function argument
1623
1624 # Type
1625
1626 ```
1627 hasPrefix :: [a] -> [a] -> Bool
1628 ```
1629
1630 # Examples
1631 :::{.example}
1632 ## `lib.lists.hasPrefix` usage example
1633
1634 ```nix
1635 hasPrefix [ 1 2 ] [ 1 2 3 4 ]
1636 => true
1637 hasPrefix [ 0 1 ] [ 1 2 3 4 ]
1638 => false
1639 ```
1640
1641 :::
1642 */
1643 hasPrefix = list1: list2: take (length list1) list2 == list1;
1644
1645 /**
1646 Remove the first list as a prefix from the second list.
1647 Error if the first list isn't a prefix of the second list.
1648
1649 # Inputs
1650
1651 `list1`
1652
1653 : 1\. Function argument
1654
1655 `list2`
1656
1657 : 2\. Function argument
1658
1659 # Type
1660
1661 ```
1662 removePrefix :: [a] -> [a] -> [a]
1663 ```
1664
1665 # Examples
1666 :::{.example}
1667 ## `lib.lists.removePrefix` usage example
1668
1669 ```nix
1670 removePrefix [ 1 2 ] [ 1 2 3 4 ]
1671 => [ 3 4 ]
1672 removePrefix [ 0 1 ] [ 1 2 3 4 ]
1673 => <error>
1674 ```
1675
1676 :::
1677 */
1678 removePrefix =
1679 list1: list2:
1680 if hasPrefix list1 list2 then
1681 drop (length list1) list2
1682 else
1683 throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument";
1684
1685 /**
1686 Returns a list consisting of at most `count` elements of `list`,
1687 starting at index `start`.
1688
1689 # Inputs
1690
1691 `start`
1692
1693 : Index at which to start the sublist
1694
1695 `count`
1696
1697 : Number of elements to take
1698
1699 `list`
1700
1701 : Input list
1702
1703 # Type
1704
1705 ```
1706 sublist :: Int -> Int -> [a] -> [a]
1707 ```
1708
1709 # Examples
1710 :::{.example}
1711 ## `lib.lists.sublist` usage example
1712
1713 ```nix
1714 sublist 1 3 [ "a" "b" "c" "d" "e" ]
1715 => [ "b" "c" "d" ]
1716 sublist 1 3 [ ]
1717 => [ ]
1718 ```
1719
1720 :::
1721 */
1722 sublist =
1723 start: count: list:
1724 let
1725 len = length list;
1726 in
1727 genList (n: elemAt list (n + start)) (
1728 if start >= len then
1729 0
1730 else if start + count > len then
1731 len - start
1732 else
1733 count
1734 );
1735
1736 /**
1737 The common prefix of two lists.
1738
1739 # Inputs
1740
1741 `list1`
1742
1743 : 1\. Function argument
1744
1745 `list2`
1746
1747 : 2\. Function argument
1748
1749 # Type
1750
1751 ```
1752 commonPrefix :: [a] -> [a] -> [a]
1753 ```
1754
1755 # Examples
1756 :::{.example}
1757 ## `lib.lists.commonPrefix` usage example
1758
1759 ```nix
1760 commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]
1761 => [ 1 2 ]
1762 commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]
1763 => [ 1 2 3 ]
1764 commonPrefix [ 1 2 3 ] [ 4 5 6 ]
1765 => [ ]
1766 ```
1767
1768 :::
1769 */
1770 commonPrefix =
1771 list1: list2:
1772 let
1773 # Zip the lists together into a list of booleans whether each element matches
1774 matchings = zipListsWith (fst: snd: fst != snd) list1 list2;
1775 # Find the first index where the elements don't match,
1776 # which will then also be the length of the common prefix.
1777 # If all elements match, we fall back to the length of the zipped list,
1778 # which is the same as the length of the smaller list.
1779 commonPrefixLength = findFirstIndex id (length matchings) matchings;
1780 in
1781 take commonPrefixLength list1;
1782
1783 /**
1784 Returns the last element of a list.
1785
1786 This function throws an error if the list is empty.
1787
1788 # Inputs
1789
1790 `list`
1791
1792 : 1\. Function argument
1793
1794 # Type
1795
1796 ```
1797 last :: [a] -> a
1798 ```
1799
1800 # Examples
1801 :::{.example}
1802 ## `lib.lists.last` usage example
1803
1804 ```nix
1805 last [ 1 2 3 ]
1806 => 3
1807 ```
1808
1809 :::
1810 */
1811 last =
1812 list:
1813 assert lib.assertMsg (list != [ ]) "lists.last: list must not be empty!";
1814 elemAt list (length list - 1);
1815
1816 /**
1817 Returns all elements but the last.
1818
1819 This function throws an error if the list is empty.
1820
1821 # Inputs
1822
1823 `list`
1824
1825 : 1\. Function argument
1826
1827 # Type
1828
1829 ```
1830 init :: [a] -> [a]
1831 ```
1832
1833 # Examples
1834 :::{.example}
1835 ## `lib.lists.init` usage example
1836
1837 ```nix
1838 init [ 1 2 3 ]
1839 => [ 1 2 ]
1840 ```
1841
1842 :::
1843 */
1844 init =
1845 list:
1846 assert lib.assertMsg (list != [ ]) "lists.init: list must not be empty!";
1847 take (length list - 1) list;
1848
1849 /**
1850 Returns the image of the cross product of some lists by a function.
1851
1852 # Examples
1853 :::{.example}
1854 ## `lib.lists.crossLists` usage example
1855
1856 ```nix
1857 crossLists (x: y: "${toString x}${toString y}") [[1 2] [3 4]]
1858 => [ "13" "14" "23" "24" ]
1859 ```
1860
1861 If you have an attrset already, consider mapCartesianProduct:
1862
1863 ```nix
1864 mapCartesianProduct (x: "${toString x.a}${toString x.b}") { a = [1 2]; b = [3 4]; }
1865 => [ "13" "14" "23" "24" ]
1866 ```
1867 :::
1868 */
1869 crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [ f ];
1870
1871 /**
1872 Remove duplicate elements from the `list`. O(n^2) complexity.
1873
1874 :::{.note}
1875 If the list only contains strings and order is not important, the complexity can be reduced to O(n log n) by using [`lib.lists.uniqueStrings`](#function-library-lib.lists.uniqueStrings) instead.
1876 :::
1877
1878 # Inputs
1879
1880 `list`
1881
1882 : Input list
1883
1884 # Type
1885
1886 ```
1887 unique :: [a] -> [a]
1888 ```
1889
1890 # Examples
1891 :::{.example}
1892 ## `lib.lists.unique` usage example
1893
1894 ```nix
1895 unique [ 3 2 3 4 ]
1896 => [ 3 2 4 ]
1897 ```
1898
1899 :::
1900 */
1901 unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [ ];
1902
1903 /**
1904 Removes duplicate strings from the `list`. O(n log n) complexity.
1905
1906 :::{.note}
1907 Order is not preserved.
1908
1909 All elements of the list must be strings without context.
1910
1911 This function fails when the list contains a non-string element or a [string with context](https://nix.dev/manual/nix/latest/language/string-context.html).
1912 In that case use [`lib.lists.unique`](#function-library-lib.lists.unique) instead.
1913 :::
1914
1915 # Inputs
1916
1917 `list`
1918
1919 : List of strings
1920
1921 # Type
1922
1923 ```
1924 uniqueStrings :: [String] -> [String]
1925 ```
1926
1927 # Examples
1928 :::{.example}
1929 ## `lib.lists.uniqueStrings` usage example
1930
1931 ```nix
1932 uniqueStrings [ "foo" "bar" "foo" ]
1933 => [ "bar" "foo" ] # order is not preserved
1934 ```
1935
1936 :::
1937 */
1938 uniqueStrings = list: attrNames (groupBy id list);
1939
1940 /**
1941 Check if list contains only unique elements. O(n^2) complexity.
1942
1943 # Inputs
1944
1945 `list`
1946
1947 : 1\. Function argument
1948
1949 # Type
1950
1951 ```
1952 allUnique :: [a] -> Bool
1953 ```
1954
1955 # Examples
1956 :::{.example}
1957 ## `lib.lists.allUnique` usage example
1958
1959 ```nix
1960 allUnique [ 3 2 3 4 ]
1961 => false
1962 allUnique [ 3 2 4 1 ]
1963 => true
1964 ```
1965
1966 :::
1967 */
1968 allUnique = list: (length (unique list) == length list);
1969
1970 /**
1971 Intersects list `list1` and another list (`list2`).
1972
1973 O(nm) complexity.
1974
1975 # Inputs
1976
1977 `list1`
1978
1979 : First list
1980
1981 `list2`
1982
1983 : Second list
1984
1985 # Type
1986
1987 ```
1988 intersectLists :: [a] -> [a] -> [a]
1989 ```
1990
1991 # Examples
1992 :::{.example}
1993 ## `lib.lists.intersectLists` usage example
1994
1995 ```nix
1996 intersectLists [ 1 2 3 ] [ 6 3 2 ]
1997 => [ 3 2 ]
1998 ```
1999
2000 :::
2001 */
2002 intersectLists = e: filter (x: elem x e);
2003
2004 /**
2005 Subtracts list `e` from another list (`list2`).
2006
2007 O(nm) complexity.
2008
2009 # Inputs
2010
2011 `e`
2012
2013 : First list
2014
2015 `list2`
2016
2017 : Second list
2018
2019 # Type
2020
2021 ```
2022 subtractLists :: [a] -> [a] -> [a]
2023 ```
2024
2025 # Examples
2026 :::{.example}
2027 ## `lib.lists.subtractLists` usage example
2028
2029 ```nix
2030 subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
2031 => [ 1 4 5 ]
2032 ```
2033
2034 :::
2035 */
2036 subtractLists = e: filter (x: !(elem x e));
2037
2038 /**
2039 Test if two lists have no common element.
2040 It should be slightly more efficient than `intersectLists a b == []`.
2041
2042 # Inputs
2043
2044 `a`
2045
2046 : 1\. Function argument
2047
2048 `b`
2049
2050 : 2\. Function argument
2051
2052 # Type
2053
2054 ```
2055 mutuallyExclusive :: [a] -> [a] -> Bool
2056 ```
2057 */
2058 mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b);
2059
2060 /**
2061 Concatenate all attributes of an attribute set.
2062 This assumes that every attribute of the set is a list.
2063
2064 # Inputs
2065
2066 `set`
2067
2068 : Attribute set with attributes that are lists
2069
2070 # Type
2071
2072 ```
2073 concatAttrValues :: { [String] :: [a] } -> [a]
2074 ```
2075
2076 # Examples
2077 :::{.example}
2078 ## `lib.concatAttrValues` usage example
2079
2080 ```nix
2081 concatAttrValues { a = [ 1 2 ]; b = [ 3 ]; }
2082 => [ 1 2 3 ]
2083 ```
2084
2085 :::
2086 */
2087 concatAttrValues = set: concatLists (attrValues set);
2088
2089 /**
2090 Replaces a list's nth element with a new element
2091
2092 # Inputs
2093
2094 `list`
2095 : Input list
2096
2097 `idx`
2098 : index to replace
2099
2100 `newElem`
2101 : new element to replace with
2102
2103 # Type
2104
2105 ```
2106 replaceElemAt :: [a] -> Int -> a -> [a]
2107 ```
2108
2109 # Examples
2110 :::{.example}
2111 ## `replaceElemAt` usage example
2112
2113 ```nix
2114 lib.replaceElemAt` [1 2 3] 0 "a"
2115 => ["a" 2 3]
2116 ```
2117
2118 :::
2119 */
2120 replaceElemAt =
2121 list: idx: newElem:
2122 assert lib.assertMsg (idx >= 0 && idx < length list)
2123 "'lists.replaceElemAt' called with index ${toString idx} on a list of size ${toString (length list)}";
2124 genList (i: if i == idx then newElem else elemAt list i) (length list);
2125}