176 lines
4.7 KiB
Nix
176 lines
4.7 KiB
Nix
lib: {
|
|
lists = {
|
|
from = {
|
|
## Convert a value to a list. If the value is already a list,
|
|
## it will be returned as-is. If the value is not a list, it
|
|
## will be wrapped in a list.
|
|
##
|
|
## @type a | (List a) -> List a
|
|
any = value:
|
|
if builtins.isList value
|
|
then value
|
|
else [value];
|
|
};
|
|
|
|
sort = {
|
|
## Perform a natural sort on a list of strings.
|
|
##
|
|
## @type List String -> List String
|
|
natural = list: let
|
|
vectorize = string: let
|
|
serialize = part:
|
|
if builtins.isList part
|
|
then lib.strings.into.int (builtins.head part)
|
|
else part;
|
|
parts = lib.strings.split "(0|[1-9][0-9]*)" string;
|
|
in
|
|
builtins.map serialize parts;
|
|
prepared = builtins.map (value: [(vectorize value) value]) list;
|
|
isLess = a: b: (lib.lists.compare lib.numbers.compare (builtins.head a) (builtins.head b)) < 0;
|
|
in
|
|
builtins.map (x: builtins.elemAt x 1) (builtins.sort isLess prepared);
|
|
};
|
|
|
|
## Map a list using both the index and value of each item. The
|
|
## index starts at 0.
|
|
##
|
|
## @type (Int -> a -> b) -> List a -> List b
|
|
mapWithIndex = f: list:
|
|
builtins.genList
|
|
(i: f i (builtins.elemAt list i))
|
|
(builtins.length list);
|
|
|
|
## Map a list using both the index and value of each item. The
|
|
## index starts at 1.
|
|
##
|
|
## @type (Int -> a -> b) -> List a -> List b
|
|
mapWithIndex1 = f: list:
|
|
builtins.genList
|
|
(i: f (i + 1) (builtins.elemAt list i))
|
|
(builtins.length list);
|
|
|
|
## Compare two lists using a custom compare function. The compare
|
|
## function is called for each element in the lists that need to
|
|
## be compared.
|
|
##
|
|
## @type (a -> b -> -1 | 0 | 1) -> List a -> List b -> Int
|
|
compare = compare: a: b: let
|
|
result = compare (builtins.head a) (builtins.head b);
|
|
in
|
|
if a == []
|
|
then
|
|
if b == []
|
|
then 0
|
|
else -1
|
|
else if b == []
|
|
then 1
|
|
else if result == 0
|
|
then lib.lists.compare compare (builtins.tail a) (builtins.tail b)
|
|
else result;
|
|
|
|
## Get the last element of a list.
|
|
##
|
|
## @type List a -> a
|
|
last = list:
|
|
assert lib.errors.trace (list != []) "List cannot be empty";
|
|
builtins.elemAt list (builtins.length list - 1);
|
|
|
|
## Slice part of a list to create a new list.
|
|
##
|
|
## @type Int -> Int -> List -> List
|
|
slice = start: count: list: let
|
|
listLength = builtins.length list;
|
|
resultLength =
|
|
if start >= listLength
|
|
then 0
|
|
else if start + count > listLength
|
|
then listLength - start
|
|
else count;
|
|
in
|
|
builtins.genList
|
|
(i: builtins.elemAt list (start + i))
|
|
resultLength;
|
|
|
|
## Take the first n elements of a list.
|
|
##
|
|
## @type Int -> List -> List
|
|
take = lib.lists.slice 0;
|
|
|
|
## Drop the first n elements of a list.
|
|
##
|
|
## @type Int -> List -> List
|
|
drop = count: list: let
|
|
listLength = builtins.length list;
|
|
in
|
|
lib.lists.slice count listLength list;
|
|
|
|
## Reverse a list.
|
|
##
|
|
## @type List -> List
|
|
reverse = list: let
|
|
length = builtins.length list;
|
|
create = i: builtins.elemAt list (length - i - 1);
|
|
in
|
|
builtins.genList create length;
|
|
|
|
## Interleave a list with a separator.
|
|
##
|
|
## @type Separator -> List -> List
|
|
intersperse = separator: list: let
|
|
length = builtins.length list;
|
|
in
|
|
if length < 2
|
|
then list
|
|
else
|
|
builtins.tail (
|
|
builtins.concatMap
|
|
(part: [separator part])
|
|
list
|
|
);
|
|
|
|
## Create a list of integers from a starting number to an ending
|
|
## number. This *includes* the ending number as well.
|
|
##
|
|
## @type Int -> Int -> List
|
|
range = start: end:
|
|
if start > end
|
|
then []
|
|
else builtins.genList (i: start + i) (end - start + 1);
|
|
|
|
## Depending on a given condition, either use the given value (as
|
|
## a list) or an empty list.
|
|
##
|
|
## @type Attrs a b => Bool -> a -> a | b
|
|
when = condition: value:
|
|
if condition
|
|
then
|
|
if builtins.isList value
|
|
then value
|
|
else [value]
|
|
else [];
|
|
|
|
## Count the number of items in a list that satisfy a given predicate.
|
|
##
|
|
## @type (a -> Bool) -> List a -> Int
|
|
count = predicate: list:
|
|
builtins.foldl' (
|
|
total: value:
|
|
if predicate value
|
|
then total + 1
|
|
else total
|
|
)
|
|
0
|
|
list;
|
|
|
|
## Remove duplicate items from a list.
|
|
##
|
|
## @type List -> List
|
|
unique = list: let
|
|
filter = result: value:
|
|
if builtins.elem value result
|
|
then result
|
|
else result ++ [value];
|
|
in
|
|
builtins.foldl' filter [] list;
|
|
};
|
|
}
|