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' :: (acc -> x -> acc) -> acc -> [x] -> acc
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 # Examples
427 :::{.example}
428 ## `lib.lists.flatten` usage example
429
430 ```nix
431 flatten [1 [2 [3] 4] 5]
432 => [1 2 3 4 5]
433 flatten 1
434 => [1]
435 ```
436
437 :::
438 */
439 flatten = x: if isList x then concatMap (y: flatten y) x else [ x ];
440
441 /**
442 Remove elements equal to `e` from a list. Useful for `buildInputs`.
443
444 # Inputs
445
446 `e`
447
448 : Element to remove from `list`
449
450 `list`
451
452 : The list
453
454 # Type
455
456 ```
457 remove :: a -> [a] -> [a]
458 ```
459
460 # Examples
461 :::{.example}
462 ## `lib.lists.remove` usage example
463
464 ```nix
465 remove 3 [ 1 3 4 3 ]
466 => [ 1 4 ]
467 ```
468
469 :::
470 */
471 remove = e: filter (x: x != e);
472
473 /**
474 Find the sole element in the list matching the specified
475 predicate.
476
477 Returns `default` if no such element exists, or
478 `multiple` if there are multiple matching elements.
479
480 # Inputs
481
482 `pred`
483
484 : Predicate
485
486 `default`
487
488 : Default value to return if element was not found.
489
490 `multiple`
491
492 : Default value to return if more than one element was found
493
494 `list`
495
496 : Input list
497
498 # Type
499
500 ```
501 findSingle :: (a -> bool) -> a -> a -> [a] -> a
502 ```
503
504 # Examples
505 :::{.example}
506 ## `lib.lists.findSingle` usage example
507
508 ```nix
509 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
510 => "multiple"
511 findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
512 => 3
513 findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
514 => "none"
515 ```
516
517 :::
518 */
519 findSingle =
520 pred: default: multiple: list:
521 let
522 found = filter pred list;
523 len = length found;
524 in
525 if len == 0 then
526 default
527 else if len != 1 then
528 multiple
529 else
530 head found;
531
532 /**
533 Find the first index in the list matching the specified
534 predicate or return `default` if no such element exists.
535
536 # Inputs
537
538 `pred`
539
540 : Predicate
541
542 `default`
543
544 : Default value to return
545
546 `list`
547
548 : Input list
549
550 # Type
551
552 ```
553 findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b)
554 ```
555
556 # Examples
557 :::{.example}
558 ## `lib.lists.findFirstIndex` usage example
559
560 ```nix
561 findFirstIndex (x: x > 3) null [ 0 6 4 ]
562 => 1
563 findFirstIndex (x: x > 9) null [ 0 6 4 ]
564 => null
565 ```
566
567 :::
568 */
569 findFirstIndex =
570 pred: default: list:
571 let
572 # A naive recursive implementation would be much simpler, but
573 # would also overflow the evaluator stack. We use `foldl'` as a workaround
574 # because it reuses the same stack space, evaluating the function for one
575 # element after another. We can't return early, so this means that we
576 # sacrifice early cutoff, but that appears to be an acceptable cost. A
577 # clever scheme with "exponential search" is possible, but appears over-
578 # engineered for now. See https://github.com/NixOS/nixpkgs/pull/235267
579
580 # Invariant:
581 # - if index < 0 then el == elemAt list (- index - 1) and all elements before el didn't satisfy pred
582 # - if index >= 0 then pred (elemAt list index) and all elements before (elemAt list index) didn't satisfy pred
583 #
584 # We start with index -1 and the 0'th element of the list, which satisfies the invariant
585 resultIndex = foldl' (
586 index: el:
587 if index < 0 then
588 # No match yet before the current index, we need to check the element
589 if pred el then
590 # We have a match! Turn it into the actual index to prevent future iterations from modifying it
591 -index - 1
592 else
593 # Still no match, update the index to the next element (we're counting down, so minus one)
594 index - 1
595 else
596 # There's already a match, propagate the index without evaluating anything
597 index
598 ) (-1) list;
599 in
600 if resultIndex < 0 then default else resultIndex;
601
602 /**
603 Find the first element in the list matching the specified
604 predicate or return `default` if no such element exists.
605
606 # Inputs
607
608 `pred`
609
610 : Predicate
611
612 `default`
613
614 : Default value to return
615
616 `list`
617
618 : Input list
619
620 # Type
621
622 ```
623 findFirst :: (a -> bool) -> a -> [a] -> a
624 ```
625
626 # Examples
627 :::{.example}
628 ## `lib.lists.findFirst` usage example
629
630 ```nix
631 findFirst (x: x > 3) 7 [ 1 6 4 ]
632 => 6
633 findFirst (x: x > 9) 7 [ 1 6 4 ]
634 => 7
635 ```
636
637 :::
638 */
639 findFirst =
640 pred: default: list:
641 let
642 index = findFirstIndex pred null list;
643 in
644 if index == null then default else elemAt list index;
645
646 /**
647 Returns true if function `pred` returns true for at least one
648 element of `list`.
649
650 # Inputs
651
652 `pred`
653
654 : Predicate
655
656 `list`
657
658 : Input list
659
660 # Type
661
662 ```
663 any :: (a -> bool) -> [a] -> bool
664 ```
665
666 # Examples
667 :::{.example}
668 ## `lib.lists.any` usage example
669
670 ```nix
671 any isString [ 1 "a" { } ]
672 => true
673 any isString [ 1 { } ]
674 => false
675 ```
676
677 :::
678 */
679 any = builtins.any;
680
681 /**
682 Returns true if function `pred` returns true for all elements of
683 `list`.
684
685 # Inputs
686
687 `pred`
688
689 : Predicate
690
691 `list`
692
693 : Input list
694
695 # Type
696
697 ```
698 all :: (a -> bool) -> [a] -> bool
699 ```
700
701 # Examples
702 :::{.example}
703 ## `lib.lists.all` usage example
704
705 ```nix
706 all (x: x < 3) [ 1 2 ]
707 => true
708 all (x: x < 3) [ 1 2 3 ]
709 => false
710 ```
711
712 :::
713 */
714 all = builtins.all;
715
716 /**
717 Count how many elements of `list` match the supplied predicate
718 function.
719
720 # Inputs
721
722 `pred`
723
724 : Predicate
725
726 # Type
727
728 ```
729 count :: (a -> bool) -> [a] -> int
730 ```
731
732 # Examples
733 :::{.example}
734 ## `lib.lists.count` usage example
735
736 ```nix
737 count (x: x == 3) [ 3 2 3 4 6 ]
738 => 2
739 ```
740
741 :::
742 */
743 count = pred: foldl' (c: x: if pred x then c + 1 else c) 0;
744
745 /**
746 Return a singleton list or an empty list, depending on a boolean
747 value. Useful when building lists with optional elements
748 (e.g. `++ optional (system == "i686-linux") firefox`).
749
750 # Inputs
751
752 `cond`
753
754 : 1\. Function argument
755
756 `elem`
757
758 : 2\. Function argument
759
760 # Type
761
762 ```
763 optional :: bool -> a -> [a]
764 ```
765
766 # Examples
767 :::{.example}
768 ## `lib.lists.optional` usage example
769
770 ```nix
771 optional true "foo"
772 => [ "foo" ]
773 optional false "foo"
774 => [ ]
775 ```
776
777 :::
778 */
779 optional = cond: elem: if cond then [ elem ] else [ ];
780
781 /**
782 Returns a list or an empty list, depending on a boolean value.
783
784 # Inputs
785
786 `cond`
787
788 : Condition
789
790 `elems`
791
792 : List to return if condition is true
793
794 # Type
795
796 ```
797 optionals :: bool -> [a] -> [a]
798 ```
799
800 # Examples
801 :::{.example}
802 ## `lib.lists.optionals` usage example
803
804 ```nix
805 optionals true [ 2 3 ]
806 => [ 2 3 ]
807 optionals false [ 2 3 ]
808 => [ ]
809 ```
810
811 :::
812 */
813 optionals = cond: elems: if cond then elems else [ ];
814
815 /**
816 If argument is a list, return it; else, wrap it in a singleton
817 list. If you're using this, you should almost certainly
818 reconsider if there isn't a more "well-typed" approach.
819
820 # Inputs
821
822 `x`
823
824 : 1\. Function argument
825
826 # Examples
827 :::{.example}
828 ## `lib.lists.toList` usage example
829
830 ```nix
831 toList [ 1 2 ]
832 => [ 1 2 ]
833 toList "hi"
834 => [ "hi" ]
835 ```
836
837 :::
838 */
839 toList = x: if isList x then x else [ x ];
840
841 /**
842 Returns a list of integers from `first` up to and including `last`.
843
844 # Inputs
845
846 `first`
847
848 : First integer in the range
849
850 `last`
851
852 : Last integer in the range
853
854 # Type
855
856 ```
857 range :: int -> int -> [int]
858 ```
859
860 # Examples
861 :::{.example}
862 ## `lib.lists.range` usage example
863
864 ```nix
865 range 2 4
866 => [ 2 3 4 ]
867 range 3 2
868 => [ ]
869 ```
870
871 :::
872 */
873 range = first: last: if first > last then [ ] else genList (n: first + n) (last - first + 1);
874
875 /**
876 Returns a list with `n` copies of an element.
877
878 # Inputs
879
880 `n`
881
882 : 1\. Function argument
883
884 `elem`
885
886 : 2\. Function argument
887
888 # Type
889
890 ```
891 replicate :: int -> a -> [a]
892 ```
893
894 # Examples
895 :::{.example}
896 ## `lib.lists.replicate` usage example
897
898 ```nix
899 replicate 3 "a"
900 => [ "a" "a" "a" ]
901 replicate 2 true
902 => [ true true ]
903 ```
904
905 :::
906 */
907 replicate = n: elem: genList (_: elem) n;
908
909 /**
910 Splits the elements of a list in two lists, `right` and
911 `wrong`, depending on the evaluation of a predicate.
912
913 # Inputs
914
915 `pred`
916
917 : Predicate
918
919 `list`
920
921 : Input list
922
923 # Type
924
925 ```
926 (a -> bool) -> [a] -> { right :: [a]; wrong :: [a]; }
927 ```
928
929 # Examples
930 :::{.example}
931 ## `lib.lists.partition` usage example
932
933 ```nix
934 partition (x: x > 2) [ 5 1 2 3 4 ]
935 => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
936 ```
937
938 :::
939 */
940 partition = builtins.partition;
941
942 /**
943 Splits the elements of a list into many lists, using the return value of a predicate.
944 Predicate should return a string which becomes keys of attrset `groupBy` returns.
945 `groupBy'` allows to customise the combining function and initial value
946
947 # Inputs
948
949 `op`
950
951 : 1\. Function argument
952
953 `nul`
954
955 : 2\. Function argument
956
957 `pred`
958
959 : 3\. Function argument
960
961 `lst`
962
963 : 4\. Function argument
964
965 # Examples
966 :::{.example}
967 ## `lib.lists.groupBy'` usage example
968
969 ```nix
970 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
971 => { true = [ 5 3 4 ]; false = [ 1 2 ]; }
972 groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";}
973 {name = "xfce"; script = "xfce4-session &";}
974 {name = "icewm"; script = "icewmbg &";}
975 {name = "mate"; script = "gnome-session &";}
976 ]
977 => { icewm = [ { name = "icewm"; script = "icewm &"; }
978 { name = "icewm"; script = "icewmbg &"; } ];
979 mate = [ { name = "mate"; script = "gnome-session &"; } ];
980 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
981 }
982
983 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
984 => { true = 12; false = 3; }
985 ```
986
987 :::
988 */
989 groupBy' =
990 op: nul: pred: lst:
991 mapAttrs (name: foldl op nul) (groupBy pred lst);
992
993 groupBy =
994 builtins.groupBy or (
995 pred:
996 foldl' (
997 r: e:
998 let
999 key = pred e;
1000 in
1001 r // { ${key} = (r.${key} or [ ]) ++ [ e ]; }
1002 ) { }
1003 );
1004
1005 /**
1006 Merges two lists of the same size together. If the sizes aren't the same
1007 the merging stops at the shortest. How both lists are merged is defined
1008 by the first argument.
1009
1010 # Inputs
1011
1012 `f`
1013
1014 : Function to zip elements of both lists
1015
1016 `fst`
1017
1018 : First list
1019
1020 `snd`
1021
1022 : Second list
1023
1024 # Type
1025
1026 ```
1027 zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
1028 ```
1029
1030 # Examples
1031 :::{.example}
1032 ## `lib.lists.zipListsWith` usage example
1033
1034 ```nix
1035 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
1036 => ["he" "lo"]
1037 ```
1038
1039 :::
1040 */
1041 zipListsWith =
1042 f: fst: snd:
1043 genList (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
1044
1045 /**
1046 Merges two lists of the same size together. If the sizes aren't the same
1047 the merging stops at the shortest.
1048
1049 # Inputs
1050
1051 `fst`
1052
1053 : First list
1054
1055 `snd`
1056
1057 : Second list
1058
1059 # Type
1060
1061 ```
1062 zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }]
1063 ```
1064
1065 # Examples
1066 :::{.example}
1067 ## `lib.lists.zipLists` usage example
1068
1069 ```nix
1070 zipLists [ 1 2 ] [ "a" "b" ]
1071 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
1072 ```
1073
1074 :::
1075 */
1076 zipLists = zipListsWith (fst: snd: { inherit fst snd; });
1077
1078 /**
1079 Reverse the order of the elements of a list.
1080
1081 # Inputs
1082
1083 `xs`
1084
1085 : 1\. Function argument
1086
1087 # Type
1088
1089 ```
1090 reverseList :: [a] -> [a]
1091 ```
1092
1093 # Examples
1094 :::{.example}
1095 ## `lib.lists.reverseList` usage example
1096
1097 ```nix
1098 reverseList [ "b" "o" "j" ]
1099 => [ "j" "o" "b" ]
1100 ```
1101
1102 :::
1103 */
1104 reverseList =
1105 xs:
1106 let
1107 l = length xs;
1108 in
1109 genList (n: elemAt xs (l - n - 1)) l;
1110
1111 /**
1112 Depth-First Search (DFS) for lists `list != []`.
1113
1114 `before a b == true` means that `b` depends on `a` (there's an
1115 edge from `b` to `a`).
1116
1117 # Inputs
1118
1119 `stopOnCycles`
1120
1121 : 1\. Function argument
1122
1123 `before`
1124
1125 : 2\. Function argument
1126
1127 `list`
1128
1129 : 3\. Function argument
1130
1131 # Examples
1132 :::{.example}
1133 ## `lib.lists.listDfs` usage example
1134
1135 ```nix
1136 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
1137 == { minimal = "/"; # minimal element
1138 visited = [ "/home/user" ]; # seen elements (in reverse order)
1139 rest = [ "/home" "other" ]; # everything else
1140 }
1141
1142 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1143 == { cycle = "/"; # cycle encountered at this element
1144 loops = [ "/" ]; # and continues to these elements
1145 visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order)
1146 rest = [ "/home" "other" ]; # everything else
1147 ```
1148
1149 :::
1150 */
1151 listDfs =
1152 stopOnCycles: before: list:
1153 let
1154 dfs' =
1155 us: visited: rest:
1156 let
1157 c = filter (x: before x us) visited;
1158 b = partition (x: before x us) rest;
1159 in
1160 if stopOnCycles && (length c > 0) then
1161 {
1162 cycle = us;
1163 loops = c;
1164 inherit visited rest;
1165 }
1166 else if length b.right == 0 then
1167 # nothing is before us
1168 {
1169 minimal = us;
1170 inherit visited rest;
1171 }
1172 else
1173 # grab the first one before us and continue
1174 dfs' (head b.right) ([ us ] ++ visited) (tail b.right ++ b.wrong);
1175 in
1176 dfs' (head list) [ ] (tail list);
1177
1178 /**
1179 Sort a list based on a partial ordering using DFS. This
1180 implementation is O(N^2), if your ordering is linear, use `sort`
1181 instead.
1182
1183 `before a b == true` means that `b` should be after `a`
1184 in the result.
1185
1186 # Inputs
1187
1188 `before`
1189
1190 : 1\. Function argument
1191
1192 `list`
1193
1194 : 2\. Function argument
1195
1196 # Examples
1197 :::{.example}
1198 ## `lib.lists.toposort` usage example
1199
1200 ```nix
1201 toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
1202 == { result = [ "/" "/home" "/home/user" "other" ]; }
1203
1204 toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1205 == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle
1206 loops = [ "/" ]; } # loops back to these elements
1207
1208 toposort hasPrefix [ "other" "/home/user" "/home" "/" ]
1209 == { result = [ "other" "/" "/home" "/home/user" ]; }
1210
1211 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
1212 ```
1213
1214 :::
1215 */
1216 toposort =
1217 before: list:
1218 let
1219 dfsthis = listDfs true before list;
1220 toporest = toposort before (dfsthis.visited ++ dfsthis.rest);
1221 in
1222 if length list < 2 then
1223 # finish
1224 { result = list; }
1225 else if dfsthis ? cycle then
1226 # there's a cycle, starting from the current vertex, return it
1227 {
1228 cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited);
1229 inherit (dfsthis) loops;
1230 }
1231 else if toporest ? cycle then
1232 # there's a cycle somewhere else in the graph, return it
1233 toporest
1234 # Slow, but short. Can be made a bit faster with an explicit stack.
1235 else
1236 # there are no cycles
1237 { result = [ dfsthis.minimal ] ++ toporest.result; };
1238
1239 /**
1240 Sort a list based on a comparator function which compares two
1241 elements and returns true if the first argument is strictly below
1242 the second argument. The returned list is sorted in an increasing
1243 order. The implementation does a quick-sort.
1244
1245 See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the
1246 default comparison on a function-derived property, and may be more efficient.
1247
1248 # Inputs
1249
1250 `comparator`
1251
1252 : 1\. Function argument
1253
1254 `list`
1255
1256 : 2\. Function argument
1257
1258 # Type
1259
1260 ```
1261 sort :: (a -> a -> Bool) -> [a] -> [a]
1262 ```
1263
1264 # Examples
1265 :::{.example}
1266 ## `lib.lists.sort` usage example
1267
1268 ```nix
1269 sort (p: q: p < q) [ 5 3 7 ]
1270 => [ 3 5 7 ]
1271 ```
1272
1273 :::
1274 */
1275 sort = builtins.sort;
1276
1277 /**
1278 Sort a list based on the default comparison of a derived property `b`.
1279
1280 The items are returned in `b`-increasing order.
1281
1282 **Performance**:
1283
1284 The passed function `f` is only evaluated once per item,
1285 unlike an unprepared [`sort`](#function-library-lib.lists.sort) using
1286 `f p < f q`.
1287
1288 **Laws**:
1289 ```nix
1290 sortOn f == sort (p: q: f p < f q)
1291 ```
1292
1293 # Inputs
1294
1295 `f`
1296
1297 : 1\. Function argument
1298
1299 `list`
1300
1301 : 2\. Function argument
1302
1303 # Type
1304
1305 ```
1306 sortOn :: (a -> b) -> [a] -> [a], for comparable b
1307 ```
1308
1309 # Examples
1310 :::{.example}
1311 ## `lib.lists.sortOn` usage example
1312
1313 ```nix
1314 sortOn stringLength [ "aa" "b" "cccc" ]
1315 => [ "b" "aa" "cccc" ]
1316 ```
1317
1318 :::
1319 */
1320 sortOn =
1321 f: list:
1322 let
1323 # Heterogenous list as pair may be ugly, but requires minimal allocations.
1324 pairs = map (x: [
1325 (f x)
1326 x
1327 ]) list;
1328 in
1329 map (x: builtins.elemAt x 1) (
1330 sort
1331 # Compare the first element of the pairs
1332 # Do not factor out the `<`, to avoid calls in hot code; duplicate instead.
1333 (a: b: head a < head b)
1334 pairs
1335 );
1336
1337 /**
1338 Compare two lists element-by-element with a comparison function `cmp`.
1339
1340 List elements are compared pairwise in order by the provided comparison function `cmp`,
1341 the first non-equal pair of elements determines the result.
1342
1343 :::{.note}
1344 The `<` operator can also be used to compare lists using a boolean condition. (e.g. `[1 2] < [1 3]` is `true`).
1345 See also [language operators](https://nix.dev/manual/nix/stable/language/operators#comparison) for more information.
1346 :::
1347
1348 # Inputs
1349
1350 `cmp`
1351
1352 : The comparison function `a: b: ...` must return:
1353 - `0` if `a` and `b` are equal
1354 - `1` if `a` is greater than `b`
1355 - `-1` if `a` is less than `b`
1356
1357 See [lib.compare](#function-library-lib.trivial.compare) for a an example implementation.
1358
1359 `a`
1360
1361 : The first list
1362
1363 `b`
1364
1365 : The second list
1366
1367 # Examples
1368 :::{.example}
1369 ## `lib.lists.compareLists` usage examples
1370
1371 ```nix
1372 compareLists lib.compare [] []
1373 => 0
1374 compareLists lib.compare [] [ "a" ]
1375 => -1
1376 compareLists lib.compare [ "a" ] []
1377 => 1
1378 compareLists lib.compare [ "a" "b" ] [ "a" "c" ]
1379 => -1
1380 ```
1381
1382 :::
1383 */
1384 compareLists =
1385 cmp: a: b:
1386 if a == [ ] then
1387 if b == [ ] then 0 else -1
1388 else if b == [ ] then
1389 1
1390 else
1391 let
1392 rel = cmp (head a) (head b);
1393 in
1394 if rel == 0 then compareLists cmp (tail a) (tail b) else rel;
1395
1396 /**
1397 Sort list using "Natural sorting".
1398 Numeric portions of strings are sorted in numeric order.
1399
1400 # Inputs
1401
1402 `lst`
1403
1404 : 1\. Function argument
1405
1406 # Examples
1407 :::{.example}
1408 ## `lib.lists.naturalSort` usage example
1409
1410 ```nix
1411 naturalSort ["disk11" "disk8" "disk100" "disk9"]
1412 => ["disk8" "disk9" "disk11" "disk100"]
1413 naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
1414 => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
1415 naturalSort ["v0.2" "v0.15" "v0.0.9"]
1416 => [ "v0.0.9" "v0.2" "v0.15" ]
1417 ```
1418
1419 :::
1420 */
1421 naturalSort =
1422 lst:
1423 let
1424 vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
1425 prepared = map (x: [
1426 (vectorise x)
1427 x
1428 ]) lst; # remember vectorised version for O(n) regex splits
1429 less = a: b: (compareLists compare (head a) (head b)) < 0;
1430 in
1431 map (x: elemAt x 1) (sort less prepared);
1432
1433 /**
1434 Returns the first (at most) N elements of a list.
1435
1436 # Inputs
1437
1438 `count`
1439
1440 : Number of elements to take
1441
1442 `list`
1443
1444 : Input list
1445
1446 # Type
1447
1448 ```
1449 take :: int -> [a] -> [a]
1450 ```
1451
1452 # Examples
1453 :::{.example}
1454 ## `lib.lists.take` usage example
1455
1456 ```nix
1457 take 2 [ "a" "b" "c" "d" ]
1458 => [ "a" "b" ]
1459 take 2 [ ]
1460 => [ ]
1461 ```
1462
1463 :::
1464 */
1465 take = count: sublist 0 count;
1466
1467 /**
1468 Returns the last (at most) N elements of a list.
1469
1470 # Inputs
1471
1472 `count`
1473
1474 : Maximum number of elements to pick
1475
1476 `list`
1477
1478 : Input list
1479
1480 # Type
1481
1482 ```
1483 takeEnd :: int -> [a] -> [a]
1484 ```
1485
1486 # Examples
1487 :::{.example}
1488 ## `lib.lists.takeEnd` usage example
1489
1490 ```nix
1491 takeEnd 2 [ "a" "b" "c" "d" ]
1492 => [ "c" "d" ]
1493 takeEnd 2 [ ]
1494 => [ ]
1495 ```
1496
1497 :::
1498 */
1499 takeEnd = n: xs: drop (max 0 (length xs - n)) xs;
1500
1501 /**
1502 Remove the first (at most) N elements of a list.
1503
1504 # Inputs
1505
1506 `count`
1507
1508 : Number of elements to drop
1509
1510 `list`
1511
1512 : Input list
1513
1514 # Type
1515
1516 ```
1517 drop :: int -> [a] -> [a]
1518 ```
1519
1520 # Examples
1521 :::{.example}
1522 ## `lib.lists.drop` usage example
1523
1524 ```nix
1525 drop 2 [ "a" "b" "c" "d" ]
1526 => [ "c" "d" ]
1527 drop 2 [ ]
1528 => [ ]
1529 ```
1530
1531 :::
1532 */
1533 drop = count: list: sublist count (length list) list;
1534
1535 /**
1536 Remove the last (at most) N elements of a list.
1537
1538 # Inputs
1539
1540 `count`
1541
1542 : Number of elements to drop
1543
1544 `list`
1545
1546 : Input list
1547
1548 # Type
1549
1550 ```
1551 dropEnd :: Int -> [a] -> [a]
1552 ```
1553
1554 # Examples
1555
1556 :::{.example}
1557 ## `lib.lists.dropEnd` usage example
1558
1559 ```nix
1560 dropEnd 2 [ "a" "b" "c" "d" ]
1561 => [ "a" "b" ]
1562 dropEnd 2 [ ]
1563 => [ ]
1564 ```
1565 :::
1566 */
1567 dropEnd = n: xs: take (max 0 (length xs - n)) xs;
1568
1569 /**
1570 Whether the first list is a prefix of the second list.
1571
1572 # Inputs
1573
1574 `list1`
1575
1576 : 1\. Function argument
1577
1578 `list2`
1579
1580 : 2\. Function argument
1581
1582 # Type
1583
1584 ```
1585 hasPrefix :: [a] -> [a] -> bool
1586 ```
1587
1588 # Examples
1589 :::{.example}
1590 ## `lib.lists.hasPrefix` usage example
1591
1592 ```nix
1593 hasPrefix [ 1 2 ] [ 1 2 3 4 ]
1594 => true
1595 hasPrefix [ 0 1 ] [ 1 2 3 4 ]
1596 => false
1597 ```
1598
1599 :::
1600 */
1601 hasPrefix = list1: list2: take (length list1) list2 == list1;
1602
1603 /**
1604 Remove the first list as a prefix from the second list.
1605 Error if the first list isn't a prefix of the second list.
1606
1607 # Inputs
1608
1609 `list1`
1610
1611 : 1\. Function argument
1612
1613 `list2`
1614
1615 : 2\. Function argument
1616
1617 # Type
1618
1619 ```
1620 removePrefix :: [a] -> [a] -> [a]
1621 ```
1622
1623 # Examples
1624 :::{.example}
1625 ## `lib.lists.removePrefix` usage example
1626
1627 ```nix
1628 removePrefix [ 1 2 ] [ 1 2 3 4 ]
1629 => [ 3 4 ]
1630 removePrefix [ 0 1 ] [ 1 2 3 4 ]
1631 => <error>
1632 ```
1633
1634 :::
1635 */
1636 removePrefix =
1637 list1: list2:
1638 if hasPrefix list1 list2 then
1639 drop (length list1) list2
1640 else
1641 throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument";
1642
1643 /**
1644 Returns a list consisting of at most `count` elements of `list`,
1645 starting at index `start`.
1646
1647 # Inputs
1648
1649 `start`
1650
1651 : Index at which to start the sublist
1652
1653 `count`
1654
1655 : Number of elements to take
1656
1657 `list`
1658
1659 : Input list
1660
1661 # Type
1662
1663 ```
1664 sublist :: int -> int -> [a] -> [a]
1665 ```
1666
1667 # Examples
1668 :::{.example}
1669 ## `lib.lists.sublist` usage example
1670
1671 ```nix
1672 sublist 1 3 [ "a" "b" "c" "d" "e" ]
1673 => [ "b" "c" "d" ]
1674 sublist 1 3 [ ]
1675 => [ ]
1676 ```
1677
1678 :::
1679 */
1680 sublist =
1681 start: count: list:
1682 let
1683 len = length list;
1684 in
1685 genList (n: elemAt list (n + start)) (
1686 if start >= len then
1687 0
1688 else if start + count > len then
1689 len - start
1690 else
1691 count
1692 );
1693
1694 /**
1695 The common prefix of two lists.
1696
1697 # Inputs
1698
1699 `list1`
1700
1701 : 1\. Function argument
1702
1703 `list2`
1704
1705 : 2\. Function argument
1706
1707 # Type
1708
1709 ```
1710 commonPrefix :: [a] -> [a] -> [a]
1711 ```
1712
1713 # Examples
1714 :::{.example}
1715 ## `lib.lists.commonPrefix` usage example
1716
1717 ```nix
1718 commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]
1719 => [ 1 2 ]
1720 commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]
1721 => [ 1 2 3 ]
1722 commonPrefix [ 1 2 3 ] [ 4 5 6 ]
1723 => [ ]
1724 ```
1725
1726 :::
1727 */
1728 commonPrefix =
1729 list1: list2:
1730 let
1731 # Zip the lists together into a list of booleans whether each element matches
1732 matchings = zipListsWith (fst: snd: fst != snd) list1 list2;
1733 # Find the first index where the elements don't match,
1734 # which will then also be the length of the common prefix.
1735 # If all elements match, we fall back to the length of the zipped list,
1736 # which is the same as the length of the smaller list.
1737 commonPrefixLength = findFirstIndex id (length matchings) matchings;
1738 in
1739 take commonPrefixLength list1;
1740
1741 /**
1742 Returns the last element of a list.
1743
1744 This function throws an error if the list is empty.
1745
1746 # Inputs
1747
1748 `list`
1749
1750 : 1\. Function argument
1751
1752 # Type
1753
1754 ```
1755 last :: [a] -> a
1756 ```
1757
1758 # Examples
1759 :::{.example}
1760 ## `lib.lists.last` usage example
1761
1762 ```nix
1763 last [ 1 2 3 ]
1764 => 3
1765 ```
1766
1767 :::
1768 */
1769 last =
1770 list:
1771 assert lib.assertMsg (list != [ ]) "lists.last: list must not be empty!";
1772 elemAt list (length list - 1);
1773
1774 /**
1775 Returns all elements but the last.
1776
1777 This function throws an error if the list is empty.
1778
1779 # Inputs
1780
1781 `list`
1782
1783 : 1\. Function argument
1784
1785 # Type
1786
1787 ```
1788 init :: [a] -> [a]
1789 ```
1790
1791 # Examples
1792 :::{.example}
1793 ## `lib.lists.init` usage example
1794
1795 ```nix
1796 init [ 1 2 3 ]
1797 => [ 1 2 ]
1798 ```
1799
1800 :::
1801 */
1802 init =
1803 list:
1804 assert lib.assertMsg (list != [ ]) "lists.init: list must not be empty!";
1805 take (length list - 1) list;
1806
1807 /**
1808 Returns the image of the cross product of some lists by a function.
1809
1810 # Examples
1811 :::{.example}
1812 ## `lib.lists.crossLists` usage example
1813
1814 ```nix
1815 crossLists (x: y: "${toString x}${toString y}") [[1 2] [3 4]]
1816 => [ "13" "14" "23" "24" ]
1817 ```
1818
1819 If you have an attrset already, consider mapCartesianProduct:
1820
1821 ```nix
1822 mapCartesianProduct (x: "${toString x.a}${toString x.b}") { a = [1 2]; b = [3 4]; }
1823 => [ "13" "14" "23" "24" ]
1824 ```
1825 :::
1826 */
1827 crossLists = f: foldl (fs: args: concatMap (f: map f args) fs) [ f ];
1828
1829 /**
1830 Remove duplicate elements from the `list`. O(n^2) complexity.
1831
1832 :::{.note}
1833 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.
1834 :::
1835
1836 # Inputs
1837
1838 `list`
1839
1840 : Input list
1841
1842 # Type
1843
1844 ```
1845 unique :: [a] -> [a]
1846 ```
1847
1848 # Examples
1849 :::{.example}
1850 ## `lib.lists.unique` usage example
1851
1852 ```nix
1853 unique [ 3 2 3 4 ]
1854 => [ 3 2 4 ]
1855 ```
1856
1857 :::
1858 */
1859 unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [ ];
1860
1861 /**
1862 Removes duplicate strings from the `list`. O(n log n) complexity.
1863
1864 :::{.note}
1865 Order is not preserved.
1866
1867 All elements of the list must be strings without context.
1868
1869 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).
1870 In that case use [`lib.lists.unique`](#function-library-lib.lists.unique) instead.
1871 :::
1872
1873 # Inputs
1874
1875 `list`
1876
1877 : List of strings
1878
1879 # Type
1880
1881 ```
1882 uniqueStrings :: [ String ] -> [ String ]
1883 ```
1884
1885 # Examples
1886 :::{.example}
1887 ## `lib.lists.uniqueStrings` usage example
1888
1889 ```nix
1890 uniqueStrings [ "foo" "bar" "foo" ]
1891 => [ "bar" "foo" ] # order is not preserved
1892 ```
1893
1894 :::
1895 */
1896 uniqueStrings = list: attrNames (groupBy id list);
1897
1898 /**
1899 Check if list contains only unique elements. O(n^2) complexity.
1900
1901 # Inputs
1902
1903 `list`
1904
1905 : 1\. Function argument
1906
1907 # Type
1908
1909 ```
1910 allUnique :: [a] -> bool
1911 ```
1912
1913 # Examples
1914 :::{.example}
1915 ## `lib.lists.allUnique` usage example
1916
1917 ```nix
1918 allUnique [ 3 2 3 4 ]
1919 => false
1920 allUnique [ 3 2 4 1 ]
1921 => true
1922 ```
1923
1924 :::
1925 */
1926 allUnique = list: (length (unique list) == length list);
1927
1928 /**
1929 Intersects list `list1` and another list (`list2`).
1930
1931 O(nm) complexity.
1932
1933 # Inputs
1934
1935 `list1`
1936
1937 : First list
1938
1939 `list2`
1940
1941 : Second list
1942
1943 # Examples
1944 :::{.example}
1945 ## `lib.lists.intersectLists` usage example
1946
1947 ```nix
1948 intersectLists [ 1 2 3 ] [ 6 3 2 ]
1949 => [ 3 2 ]
1950 ```
1951
1952 :::
1953 */
1954 intersectLists = e: filter (x: elem x e);
1955
1956 /**
1957 Subtracts list `e` from another list (`list2`).
1958
1959 O(nm) complexity.
1960
1961 # Inputs
1962
1963 `e`
1964
1965 : First list
1966
1967 `list2`
1968
1969 : Second list
1970
1971 # Examples
1972 :::{.example}
1973 ## `lib.lists.subtractLists` usage example
1974
1975 ```nix
1976 subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
1977 => [ 1 4 5 ]
1978 ```
1979
1980 :::
1981 */
1982 subtractLists = e: filter (x: !(elem x e));
1983
1984 /**
1985 Test if two lists have no common element.
1986 It should be slightly more efficient than `intersectLists a b == []`.
1987
1988 # Inputs
1989
1990 `a`
1991
1992 : 1\. Function argument
1993
1994 `b`
1995
1996 : 2\. Function argument
1997 */
1998 mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b);
1999
2000 /**
2001 Concatenate all attributes of an attribute set.
2002 This assumes that every attribute of the set is a list.
2003
2004 # Inputs
2005
2006 `set`
2007
2008 : Attribute set with attributes that are lists
2009
2010 # Examples
2011 :::{.example}
2012 ## `lib.concatAttrValues` usage example
2013
2014 ```nix
2015 concatAttrValues { a = [ 1 2 ]; b = [ 3 ]; }
2016 => [ 1 2 3 ]
2017 ```
2018
2019 :::
2020 */
2021 concatAttrValues = set: concatLists (attrValues set);
2022
2023 /**
2024 Replaces a list's nth element with a new element
2025
2026 # Inputs
2027
2028 `list`
2029 : Input list
2030
2031 `idx`
2032 : index to replace
2033
2034 `newElem`
2035 : new element to replace with
2036
2037 # Type
2038
2039 ```
2040 replaceElemAt :: [a] -> int - b -> [a]
2041 ```
2042
2043 # Examples
2044 :::{.example}
2045 ## `replaceElemAt` usage example
2046
2047 ```nix
2048 lib.replaceElemAt` [1 2 3] 0 "a"
2049 => ["a" 2 3]
2050 ```
2051
2052 :::
2053 */
2054 replaceElemAt =
2055 list: idx: newElem:
2056 assert lib.assertMsg (idx >= 0 && idx < length list)
2057 "'lists.replaceElemAt' called with index ${toString idx} on a list of size ${toString (length list)}";
2058 genList (i: if i == idx then newElem else elemAt list i) (length list);
2059}