2 General list operations.
6 inherit (lib.strings) toInt;
7 inherit (lib.trivial) compare min id warn pipe;
8 inherit (lib.attrsets) mapAttrs;
12 inherit (builtins) head tail length isList elemAt concatLists filter elem genList map;
15 Create a list consisting of a single element. `singleton x` is
16 sometimes more convenient with respect to indentation than `[x]`
17 when x spans multiple lines.
23 : 1\. Function argument
33 ## `lib.lists.singleton` usage example
45 Apply the function to each element in the list.
46 Same as `map`, but arguments flipped.
52 : 1\. Function argument
56 : 2\. Function argument
61 forEach :: [a] -> (a -> b) -> [b]
66 ## `lib.lists.forEach` usage example
77 forEach = xs: f: map f xs;
80 “right fold” a binary function `op` between successive elements of
81 `list` with `nul` as the starting value, i.e.,
82 `foldr op nul [x_1 x_2 ... x_n] == op x_1 (op x_2 ... (op x_n nul))`.
89 : 1\. Function argument
93 : 2\. Function argument
97 : 3\. Function argument
102 foldr :: (a -> b -> b) -> b -> [a] -> b
107 ## `lib.lists.foldr` usage example
110 concat = foldr (a: b: a + b) "z"
111 concat [ "a" "b" "c" ]
114 strange = foldr (int: str: toString (int + 1) + str) "a"
121 foldr = op: nul: list:
127 else op (elemAt list n) (fold' (n + 1));
131 `fold` is an alias of `foldr` for historic reasons
133 # FIXME(Profpatsch): deprecate?
138 “left fold”, like `foldr`, but from the left:
140 `foldl op nul [x_1 x_2 ... x_n] == op (... (op (op nul x_1) x_2) ... x_n)`.
146 : 1\. Function argument
150 : 2\. Function argument
154 : 3\. Function argument
159 foldl :: (b -> a -> b) -> b -> [a] -> b
164 ## `lib.lists.foldl` usage example
167 lconcat = foldl (a: b: a + b) "z"
168 lconcat [ "a" "b" "c" ]
171 lstrange = foldl (str: int: str + toString (int + 1)) "a"
178 foldl = op: nul: list:
183 else op (foldl' (n - 1)) (elemAt list n);
184 in foldl' (length list - 1);
187 Reduce a list by applying a binary operator from left to right,
188 starting with an initial accumulator.
190 Before each application of the operator, the accumulator value is evaluated.
191 This behavior makes this function stricter than [`foldl`](#function-library-lib.lists.foldl).
193 Unlike [`builtins.foldl'`](https://nixos.org/manual/nix/unstable/language/builtins.html#builtins-foldl'),
194 the initial accumulator argument is evaluated before the first iteration.
199 foldl' op acc₀ [ x₀ x₁ x₂ ... xₙ₋₁ xₙ ]
202 is (denotationally) equivalent to the following,
203 but with the added benefit that `foldl'` itself will never overflow the stack.
207 acc₁ = builtins.seq acc₀ (op acc₀ x₀ );
208 acc₂ = builtins.seq acc₁ (op acc₁ x₁ );
209 acc₃ = builtins.seq acc₂ (op acc₂ x₂ );
211 accₙ = builtins.seq accₙ₋₁ (op accₙ₋₁ xₙ₋₁);
212 accₙ₊₁ = builtins.seq accₙ (op accₙ xₙ );
216 # Or ignoring builtins.seq
217 op (op (... (op (op (op acc₀ x₀) x₁) x₂) ...) xₙ₋₁) xₙ
224 : The binary operation to run, where the two arguments are:
226 1. `acc`: The current accumulator value: Either the initial one for the first iteration, or the result of the previous iteration
227 2. `x`: The corresponding list element for this iteration
231 : The initial accumulator value.
233 The accumulator value is evaluated in any case before the first iteration starts.
235 To avoid evaluation even before the `list` argument is given an eta expansion can be used:
238 list: lib.foldl' op acc list
248 foldl' :: (acc -> x -> acc) -> acc -> [x] -> acc
253 ## `lib.lists.foldl'` usage example
256 foldl' (acc: x: acc + x) 0 [1 2 3]
265 # The builtin `foldl'` is a bit lazier than one might expect.
266 # See https://github.com/NixOS/nix/pull/7158.
267 # In particular, the initial accumulator value is not forced before the first iteration starts.
269 (builtins.foldl' op acc);
272 Map with index starting from 0
278 : 1\. Function argument
282 : 2\. Function argument
287 imap0 :: (int -> a -> b) -> [a] -> [b]
292 ## `lib.lists.imap0` usage example
295 imap0 (i: v: "${v}-${toString i}") ["a" "b"]
301 imap0 = f: list: genList (n: f n (elemAt list n)) (length list);
304 Map with index starting from 1
311 : 1\. Function argument
315 : 2\. Function argument
320 imap1 :: (int -> a -> b) -> [a] -> [b]
325 ## `lib.lists.imap1` usage example
328 imap1 (i: v: "${v}-${toString i}") ["a" "b"]
334 imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);
337 Filter a list for elements that satisfy a predicate function.
338 The predicate function is called with both the index and value for each element.
339 It must return `true`/`false` to include/exclude a given element in the result.
340 This function is strict in the result of the predicate function for each element.
341 This function has O(n) complexity.
343 Also see [`builtins.filter`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filter) (available as `lib.lists.filter`),
344 which can be used instead when the index isn't needed.
350 : The predicate function, it takes two arguments:
351 - 1. (int): the index of the element.
352 - 2. (a): the value of the element.
354 It must return `true`/`false` to include/exclude a given element from the result.
358 : The list to filter using the predicate.
362 ifilter0 :: (int -> a -> bool) -> [a] -> [a]
367 ## `lib.lists.ifilter0` usage example
370 ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ]
378 map (idx: elemAt input idx) (
379 filter (idx: ipred idx (elemAt input idx)) (
380 genList (x: x) (length input)
385 Map and concatenate the result.
390 concatMap :: (a -> [b]) -> [a] -> [b]
395 ## `lib.lists.concatMap` usage example
398 concatMap (x: [x] ++ ["z"]) ["a" "b"]
399 => [ "a" "z" "b" "z" ]
404 concatMap = builtins.concatMap;
407 Flatten the argument into a single list; that is, nested lists are
408 spliced into the top-level lists.
415 : 1\. Function argument
420 ## `lib.lists.flatten` usage example
423 flatten [1 [2 [3] 4] 5]
433 then concatMap (y: flatten y) x
437 Remove elements equal to 'e' from a list. Useful for buildInputs.
444 : Element to remove from `list`
453 remove :: a -> [a] -> [a]
458 ## `lib.lists.remove` usage example
468 e: filter (x: x != e);
471 Find the sole element in the list matching the specified
474 Returns `default` if no such element exists, or
475 `multiple` if there are multiple matching elements.
486 : Default value to return if element was not found.
490 : Default value to return if more than one element was found
499 findSingle :: (a -> bool) -> a -> a -> [a] -> a
504 ## `lib.lists.findSingle` usage example
507 findSingle (x: x == 3) "none" "multiple" [ 1 3 3 ]
509 findSingle (x: x == 3) "none" "multiple" [ 1 3 ]
511 findSingle (x: x == 3) "none" "multiple" [ 1 9 ]
522 let found = filter pred list; len = length found;
523 in if len == 0 then default
524 else if len != 1 then multiple
528 Find the first index in the list matching the specified
529 predicate or return `default` if no such element exists.
539 : Default value to return
548 findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b)
553 ## `lib.lists.findFirstIndex` usage example
556 findFirstIndex (x: x > 3) null [ 0 6 4 ]
558 findFirstIndex (x: x > 9) null [ 0 6 4 ]
569 # A naive recursive implementation would be much simpler, but
570 # would also overflow the evaluator stack. We use `foldl'` as a workaround
571 # because it reuses the same stack space, evaluating the function for one
572 # element after another. We can't return early, so this means that we
573 # sacrifice early cutoff, but that appears to be an acceptable cost. A
574 # clever scheme with "exponential search" is possible, but appears over-
575 # engineered for now. See https://github.com/NixOS/nixpkgs/pull/235267
578 # - if index < 0 then el == elemAt list (- index - 1) and all elements before el didn't satisfy pred
579 # - if index >= 0 then pred (elemAt list index) and all elements before (elemAt list index) didn't satisfy pred
581 # We start with index -1 and the 0'th element of the list, which satisfies the invariant
582 resultIndex = foldl' (index: el:
584 # No match yet before the current index, we need to check the element
586 # We have a match! Turn it into the actual index to prevent future iterations from modifying it
589 # Still no match, update the index to the next element (we're counting down, so minus one)
592 # There's already a match, propagate the index without evaluating anything
596 if resultIndex < 0 then
602 Find the first element in the list matching the specified
603 predicate or return `default` if no such element exists.
613 : Default value to return
622 findFirst :: (a -> bool) -> a -> [a] -> a
627 ## `lib.lists.findFirst` usage example
630 findFirst (x: x > 3) 7 [ 1 6 4 ]
632 findFirst (x: x > 9) 7 [ 1 6 4 ]
643 index = findFirstIndex pred null list;
645 if index == null then
651 Return true if function `pred` returns true for at least one
667 any :: (a -> bool) -> [a] -> bool
672 ## `lib.lists.any` usage example
675 any isString [ 1 "a" { } ]
677 any isString [ 1 { } ]
686 Return true if function `pred` returns true for all elements of
702 all :: (a -> bool) -> [a] -> bool
707 ## `lib.lists.all` usage example
710 all (x: x < 3) [ 1 2 ]
712 all (x: x < 3) [ 1 2 3 ]
721 Count how many elements of `list` match the supplied predicate
733 count :: (a -> bool) -> [a] -> int
738 ## `lib.lists.count` usage example
741 count (x: x == 3) [ 3 2 3 4 6 ]
748 pred: foldl' (c: x: if pred x then c + 1 else c) 0;
751 Return a singleton list or an empty list, depending on a boolean
752 value. Useful when building lists with optional elements
753 (e.g. `++ optional (system == "i686-linux") firefox`).
759 : 1\. Function argument
763 : 2\. Function argument
768 optional :: bool -> a -> [a]
773 ## `lib.lists.optional` usage example
784 optional = cond: elem: if cond then [elem] else [];
787 Return a list or an empty list, depending on a boolean value.
797 : List to return if condition is true
802 optionals :: bool -> [a] -> [a]
807 ## `lib.lists.optionals` usage example
810 optionals true [ 2 3 ]
812 optionals false [ 2 3 ]
820 elems: if cond then elems else [];
824 If argument is a list, return it; else, wrap it in a singleton
825 list. If you're using this, you should almost certainly
826 reconsider if there isn't a more "well-typed" approach.
832 : 1\. Function argument
836 ## `lib.lists.toList` usage example
847 toList = x: if isList x then x else [x];
850 Return a list of integers from `first` up to and including `last`.
856 : First integer in the range
860 : Last integer in the range
865 range :: int -> int -> [int]
870 ## `lib.lists.range` usage example
887 genList (n: first + n) (last - first + 1);
890 Return a list with `n` copies of an element.
896 : 1\. Function argument
900 : 2\. Function argument
905 replicate :: int -> a -> [a]
910 ## `lib.lists.replicate` usage example
921 replicate = n: elem: genList (_: elem) n;
924 Splits the elements of a list in two lists, `right` and
925 `wrong`, depending on the evaluation of a predicate.
940 (a -> bool) -> [a] -> { right :: [a]; wrong :: [a]; }
945 ## `lib.lists.partition` usage example
948 partition (x: x > 2) [ 5 1 2 3 4 ]
949 => { right = [ 5 3 4 ]; wrong = [ 1 2 ]; }
954 partition = builtins.partition;
957 Splits the elements of a list into many lists, using the return value of a predicate.
958 Predicate should return a string which becomes keys of attrset `groupBy` returns.
959 `groupBy'` allows to customise the combining function and initial value
965 : 1\. Function argument
969 : 2\. Function argument
973 : 3\. Function argument
977 : 4\. Function argument
982 ## `lib.lists.groupBy'` usage example
985 groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
986 => { true = [ 5 3 4 ]; false = [ 1 2 ]; }
987 groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";}
988 {name = "xfce"; script = "xfce4-session &";}
989 {name = "icewm"; script = "icewmbg &";}
990 {name = "mate"; script = "gnome-session &";}
992 => { icewm = [ { name = "icewm"; script = "icewm &"; }
993 { name = "icewm"; script = "icewmbg &"; } ];
994 mate = [ { name = "mate"; script = "gnome-session &"; } ];
995 xfce = [ { name = "xfce"; script = "xfce4-session &"; } ];
998 groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ]
999 => { true = 12; false = 3; }
1004 groupBy' = op: nul: pred: lst: mapAttrs (name: foldl op nul) (groupBy pred lst);
1006 groupBy = builtins.groupBy or (
1011 r // { ${key} = (r.${key} or []) ++ [e]; }
1015 Merges two lists of the same size together. If the sizes aren't the same
1016 the merging stops at the shortest. How both lists are merged is defined
1017 by the first argument.
1023 : Function to zip elements of both lists
1036 zipListsWith :: (a -> b -> c) -> [a] -> [b] -> [c]
1041 ## `lib.lists.zipListsWith` usage example
1044 zipListsWith (a: b: a + b) ["h" "l"] ["e" "o"]
1055 (n: f (elemAt fst n) (elemAt snd n)) (min (length fst) (length snd));
1058 Merges two lists of the same size together. If the sizes aren't the same
1059 the merging stops at the shortest.
1074 zipLists :: [a] -> [b] -> [{ fst :: a; snd :: b; }]
1079 ## `lib.lists.zipLists` usage example
1082 zipLists [ 1 2 ] [ "a" "b" ]
1083 => [ { fst = 1; snd = "a"; } { fst = 2; snd = "b"; } ]
1088 zipLists = zipListsWith (fst: snd: { inherit fst snd; });
1091 Reverse the order of the elements of a list.
1097 : 1\. Function argument
1102 reverseList :: [a] -> [a]
1107 ## `lib.lists.reverseList` usage example
1110 reverseList [ "b" "o" "j" ]
1117 let l = length xs; in genList (n: elemAt xs (l - n - 1)) l;
1120 Depth-First Search (DFS) for lists `list != []`.
1122 `before a b == true` means that `b` depends on `a` (there's an
1123 edge from `b` to `a`).
1130 : 1\. Function argument
1134 : 2\. Function argument
1138 : 3\. Function argument
1143 ## `lib.lists.listDfs` usage example
1146 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" ]
1147 == { minimal = "/"; # minimal element
1148 visited = [ "/home/user" ]; # seen elements (in reverse order)
1149 rest = [ "/home" "other" ]; # everything else
1152 listDfs true hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1153 == { cycle = "/"; # cycle encountered at this element
1154 loops = [ "/" ]; # and continues to these elements
1155 visited = [ "/" "/home/user" ]; # elements leading to the cycle (in reverse order)
1156 rest = [ "/home" "other" ]; # everything else
1161 listDfs = stopOnCycles: before: list:
1163 dfs' = us: visited: rest:
1165 c = filter (x: before x us) visited;
1166 b = partition (x: before x us) rest;
1167 in if stopOnCycles && (length c > 0)
1168 then { cycle = us; loops = c; inherit visited rest; }
1169 else if length b.right == 0
1170 then # nothing is before us
1171 { minimal = us; inherit visited rest; }
1172 else # grab the first one before us and continue
1175 (tail b.right ++ b.wrong);
1176 in dfs' (head list) [] (tail list);
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`
1183 `before a b == true` means that `b` should be after `a`
1191 : 1\. Function argument
1195 : 2\. Function argument
1200 ## `lib.lists.toposort` usage example
1203 toposort hasPrefix [ "/home/user" "other" "/" "/home" ]
1204 == { result = [ "/" "/home" "/home/user" "other" ]; }
1206 toposort hasPrefix [ "/home/user" "other" "/" "/home" "/" ]
1207 == { cycle = [ "/home/user" "/" "/" ]; # path leading to a cycle
1208 loops = [ "/" ]; } # loops back to these elements
1210 toposort hasPrefix [ "other" "/home/user" "/home" "/" ]
1211 == { result = [ "other" "/" "/home" "/home/user" ]; }
1213 toposort (a: b: a < b) [ 3 2 1 ] == { result = [ 1 2 3 ]; }
1218 toposort = before: list:
1220 dfsthis = listDfs true before list;
1221 toporest = toposort before (dfsthis.visited ++ dfsthis.rest);
1226 else if dfsthis ? cycle
1227 then # there's a cycle, starting from the current vertex, return it
1228 { cycle = reverseList ([ dfsthis.cycle ] ++ dfsthis.visited);
1229 inherit (dfsthis) loops; }
1230 else if toporest ? cycle
1231 then # there's a cycle somewhere else in the graph, return it
1233 # Slow, but short. Can be made a bit faster with an explicit stack.
1234 else # there are no cycles
1235 { result = [ dfsthis.minimal ] ++ toporest.result; };
1238 Sort a list based on a comparator function which compares two
1239 elements and returns true if the first argument is strictly below
1240 the second argument. The returned list is sorted in an increasing
1241 order. The implementation does a quick-sort.
1243 See also [`sortOn`](#function-library-lib.lists.sortOn), which applies the
1244 default comparison on a function-derived property, and may be more efficient.
1250 : 1\. Function argument
1254 : 2\. Function argument
1259 sort :: (a -> a -> Bool) -> [a] -> [a]
1264 ## `lib.lists.sort` usage example
1267 sort (p: q: p < q) [ 5 3 7 ]
1273 sort = builtins.sort;
1276 Sort a list based on the default comparison of a derived property `b`.
1278 The items are returned in `b`-increasing order.
1282 The passed function `f` is only evaluated once per item,
1283 unlike an unprepared [`sort`](#function-library-lib.lists.sort) using
1288 sortOn f == sort (p: q: f p < f q)
1296 : 1\. Function argument
1300 : 2\. Function argument
1305 sortOn :: (a -> b) -> [a] -> [a], for comparable b
1310 ## `lib.lists.sortOn` usage example
1313 sortOn stringLength [ "aa" "b" "cccc" ]
1314 => [ "b" "aa" "cccc" ]
1321 # Heterogenous list as pair may be ugly, but requires minimal allocations.
1322 pairs = map (x: [(f x) x]) list;
1325 (x: builtins.elemAt x 1)
1327 # Compare the first element of the pairs
1328 # Do not factor out the `<`, to avoid calls in hot code; duplicate instead.
1329 (a: b: head a < head b)
1333 Compare two lists element-by-element.
1339 : 1\. Function argument
1343 : 2\. Function argument
1347 : 3\. Function argument
1352 ## `lib.lists.compareLists` usage example
1355 compareLists compare [] []
1357 compareLists compare [] [ "a" ]
1359 compareLists compare [ "a" ] []
1361 compareLists compare [ "a" "b" ] [ "a" "c" ]
1367 compareLists = cmp: a: b:
1374 else let rel = cmp (head a) (head b); in
1376 then compareLists cmp (tail a) (tail b)
1380 Sort list using "Natural sorting".
1381 Numeric portions of strings are sorted in numeric order.
1388 : 1\. Function argument
1393 ## `lib.lists.naturalSort` usage example
1396 naturalSort ["disk11" "disk8" "disk100" "disk9"]
1397 => ["disk8" "disk9" "disk11" "disk100"]
1398 naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
1399 => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
1400 naturalSort ["v0.2" "v0.15" "v0.0.9"]
1401 => [ "v0.0.9" "v0.2" "v0.15" ]
1408 vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
1409 prepared = map (x: [ (vectorise x) x ]) lst; # remember vectorised version for O(n) regex splits
1410 less = a: b: (compareLists compare (head a) (head b)) < 0;
1412 map (x: elemAt x 1) (sort less prepared);
1415 Return the first (at most) N elements of a list.
1422 : Number of elements to take
1431 take :: int -> [a] -> [a]
1436 ## `lib.lists.take` usage example
1439 take 2 [ "a" "b" "c" "d" ]
1448 count: sublist 0 count;
1451 Remove the first (at most) N elements of a list.
1458 : Number of elements to drop
1467 drop :: int -> [a] -> [a]
1472 ## `lib.lists.drop` usage example
1475 drop 2 [ "a" "b" "c" "d" ]
1485 list: sublist count (length list) list;
1488 Whether the first list is a prefix of the second list.
1495 : 1\. Function argument
1499 : 2\. Function argument
1504 hasPrefix :: [a] -> [a] -> bool
1509 ## `lib.lists.hasPrefix` usage example
1512 hasPrefix [ 1 2 ] [ 1 2 3 4 ]
1514 hasPrefix [ 0 1 ] [ 1 2 3 4 ]
1523 take (length list1) list2 == list1;
1526 Remove the first list as a prefix from the second list.
1527 Error if the first list isn't a prefix of the second list.
1533 : 1\. Function argument
1537 : 2\. Function argument
1542 removePrefix :: [a] -> [a] -> [a]
1547 ## `lib.lists.removePrefix` usage example
1550 removePrefix [ 1 2 ] [ 1 2 3 4 ]
1552 removePrefix [ 0 1 ] [ 1 2 3 4 ]
1561 if hasPrefix list1 list2 then
1562 drop (length list1) list2
1564 throw "lib.lists.removePrefix: First argument is not a list prefix of the second argument";
1567 Return a list consisting of at most `count` elements of `list`,
1568 starting at index `start`.
1574 : Index at which to start the sublist
1578 : Number of elements to take
1587 sublist :: int -> int -> [a] -> [a]
1592 ## `lib.lists.sublist` usage example
1595 sublist 1 3 [ "a" "b" "c" "d" "e" ]
1607 let len = length list; in
1609 (n: elemAt list (n + start))
1610 (if start >= len then 0
1611 else if start + count > len then len - start
1615 The common prefix of two lists.
1622 : 1\. Function argument
1626 : 2\. Function argument
1631 commonPrefix :: [a] -> [a] -> [a]
1636 ## `lib.lists.commonPrefix` usage example
1639 commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]
1641 commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]
1643 commonPrefix [ 1 2 3 ] [ 4 5 6 ]
1653 # Zip the lists together into a list of booleans whether each element matches
1654 matchings = zipListsWith (fst: snd: fst != snd) list1 list2;
1655 # Find the first index where the elements don't match,
1656 # which will then also be the length of the common prefix.
1657 # If all elements match, we fall back to the length of the zipped list,
1658 # which is the same as the length of the smaller list.
1659 commonPrefixLength = findFirstIndex id (length matchings) matchings;
1661 take commonPrefixLength list1;
1664 Return the last element of a list.
1666 This function throws an error if the list is empty.
1673 : 1\. Function argument
1683 ## `lib.lists.last` usage example
1693 assert lib.assertMsg (list != []) "lists.last: list must not be empty!";
1694 elemAt list (length list - 1);
1697 Return all elements but the last.
1699 This function throws an error if the list is empty.
1706 : 1\. Function argument
1716 ## `lib.lists.init` usage example
1726 assert lib.assertMsg (list != []) "lists.init: list must not be empty!";
1727 take (length list - 1) list;
1731 Return the image of the cross product of some lists by a function.
1736 ## `lib.lists.crossLists` usage example
1739 crossLists (x: y: "${toString x}${toString y}") [[1 2] [3 4]]
1740 => [ "13" "14" "23" "24" ]
1743 The following function call is equivalent to the one deprecated above:
1746 mapCartesianProduct (x: "${toString x.a}${toString x.b}") { a = [1 2]; b = [3 4]; }
1747 => [ "13" "14" "23" "24" ]
1752 ''lib.crossLists is deprecated, use lib.mapCartesianProduct instead.
1754 For example, the following function call:
1756 nix-repl> lib.crossLists (x: y: x+y) [[1 2] [3 4]]
1759 Can now be replaced by the following one:
1761 nix-repl> lib.mapCartesianProduct ({x,y}: x+y) { x = [1 2]; y = [3 4]; }
1764 (f: foldl (fs: args: concatMap (f: map f args) fs) [f]);
1767 Remove duplicate elements from the `list`. O(n^2) complexity.
1779 unique :: [a] -> [a]
1784 ## `lib.lists.unique` usage example
1793 unique = foldl' (acc: e: if elem e acc then acc else acc ++ [ e ]) [];
1796 Check if list contains only unique elements. O(n^2) complexity.
1803 : 1\. Function argument
1808 allUnique :: [a] -> bool
1813 ## `lib.lists.allUnique` usage example
1816 allUnique [ 3 2 3 4 ]
1818 allUnique [ 3 2 4 1 ]
1824 allUnique = list: (length (unique list) == length list);
1828 Intersects list 'list1' and another list (`list2`).
1845 ## `lib.lists.intersectLists` usage example
1848 intersectLists [ 1 2 3 ] [ 6 3 2 ]
1854 intersectLists = e: filter (x: elem x e);
1857 Subtracts list 'e' from another list (`list2`).
1874 ## `lib.lists.subtractLists` usage example
1877 subtractLists [ 3 2 ] [ 1 2 3 4 5 3 ]
1883 subtractLists = e: filter (x: !(elem x e));
1886 Test if two lists have no common element.
1887 It should be slightly more efficient than (intersectLists a b == [])
1893 : 1\. Function argument
1897 : 2\. Function argument
1899 mutuallyExclusive = a: b: length a == 0 || !(any (x: elem x a) b);