feat: add support for cartesian products

This commit is contained in:
Jake Hamilton 2025-09-01 02:43:53 -07:00
parent c55943c5e8
commit 2af4e9f1d5
Signed by: jakehamilton
GPG key ID: 9762169A1B35EA68
2 changed files with 71 additions and 13 deletions

View file

@ -23,10 +23,12 @@ lib: {
parts = lib.strings.split "(0|[1-9][0-9]*)" string;
in
builtins.map serialize parts;
prepared = builtins.map (value: [
(vectorize value)
value
]) list;
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);
@ -86,6 +88,23 @@ lib: {
process (builtins.head list) [ ] (builtins.tail list);
};
cartesian = {
product = domain:
let
names = builtins.attrNames domain;
process =
results: name:
builtins.concatMap
(result: builtins.map (values: result // { ${name} = values; }) domain.${name})
results;
in
builtins.foldl' process [{ }] names;
map = f: domain:
builtins.map f (lib.lists.cartesian.product domain);
};
## Map a list using both the index and value of each item. The
## index starts at 0.
##
@ -123,8 +142,8 @@ lib: {
## @type List a -> a
last =
list:
assert lib.errors.trace (list != [ ]) "List cannot be empty";
builtins.elemAt list (builtins.length list - 1);
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.
##
@ -163,8 +182,8 @@ lib: {
## @type List -> List
init =
list:
assert lib.errors.trace (builtins.length list != 0) "lib.lists.init: list must not be empty.";
lib.lists.take (builtins.length list - 1) list;
assert lib.errors.trace (builtins.length list != 0) "lib.lists.init: list must not be empty.";
lib.lists.take (builtins.length list - 1) list;
## Reverse a list.
##
@ -189,10 +208,12 @@ lib: {
list
else
builtins.tail (
builtins.concatMap (part: [
separator
part
]) list
builtins.concatMap
(part: [
separator
part
])
list
);
## Create a list of integers from a starting number to an ending

View file

@ -45,6 +45,43 @@ in
};
};
"cartesian" = {
"product" = {
"computes the cartesian product of two lists" =
let
expected = [
{ x = 1; y = "a"; }
{ x = 1; y = "b"; }
{ x = 2; y = "a"; }
{ x = 2; y = "b"; }
];
actual = lib.lists.cartesian.product {
x = [ 1 2 ];
y = [ "a" "b" ];
};
in
actual == expected;
};
"map" = {
"maps over the cartesian product of two lists" =
let
expected = [
"1-a"
"1-b"
"2-a"
"2-b"
];
actual = lib.lists.cartesian.map ({ x, y }: "${builtins.toString x}-${y}") {
x = [ 1 2 ];
y = [ "a" "b" ];
};
in
(builtins.trace (builtins.deepSeq actual actual))
actual == expected;
};
};
"mapWithIndex" = {
"maps a list using index 0" =
let
@ -152,7 +189,7 @@ in
actual = lib.lists.last [ ];
evaluated = builtins.tryEval actual;
in
!evaluated.success;
!evaluated.success;
};
"slice" = {