summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorJacek Galowicz <jacek@galowicz.de>2021-01-25 16:59:46 +0100
committerJacek Galowicz <jacek@galowicz.de>2021-01-28 23:08:59 +0100
commit123045a57056b997165be4963cbf62120a967fec (patch)
treedf971067e1c59e11fba585a121f060a3a49bd93d /lib
parentd9353519d70454b53c6c302205272ccac81e1b7f (diff)
downloadnixpkgs-123045a57056b997165be4963cbf62120a967fec.tar
nixpkgs-123045a57056b997165be4963cbf62120a967fec.tar.gz
nixpkgs-123045a57056b997165be4963cbf62120a967fec.tar.bz2
nixpkgs-123045a57056b997165be4963cbf62120a967fec.tar.lz
nixpkgs-123045a57056b997165be4963cbf62120a967fec.tar.xz
nixpkgs-123045a57056b997165be4963cbf62120a967fec.tar.zst
nixpkgs-123045a57056b997165be4963cbf62120a967fec.zip
lib/attrsets: add cartesianProductOfSets function
Diffstat (limited to 'lib')
-rw-r--r--lib/attrsets.nix19
-rw-r--r--lib/default.nix2
-rw-r--r--lib/tests/misc.nix67
3 files changed, 86 insertions, 2 deletions
diff --git a/lib/attrsets.nix b/lib/attrsets.nix
index d91d7a0cd47..0ce3aaeca45 100644
--- a/lib/attrsets.nix
+++ b/lib/attrsets.nix
@@ -183,6 +183,24 @@ rec {
     else
       [];
 
+  /* Return the cartesian product of attribute set value combinations.
+
+    Example:
+      cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; }
+      => [
+           { a = 1; b = 10; }
+           { a = 1; b = 20; }
+           { a = 2; b = 10; }
+           { a = 2; b = 20; }
+         ]
+  */
+  cartesianProductOfSets = attrsOfLists:
+    lib.foldl' (listOfAttrs: attrName:
+      concatMap (attrs:
+        map (listValue: attrs // { ${attrName} = listValue; }) attrsOfLists.${attrName}
+      ) listOfAttrs
+    ) [{}] (attrNames attrsOfLists);
+
 
   /* Utility function that creates a {name, value} pair as expected by
      builtins.listToAttrs.
@@ -493,5 +511,4 @@ rec {
   zipWithNames = zipAttrsWithNames;
   zip = builtins.trace
     "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;
-
 }
diff --git a/lib/default.nix b/lib/default.nix
index 803f1f76564..50320669e28 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -78,7 +78,7 @@ let
       zipAttrsWithNames zipAttrsWith zipAttrs recursiveUpdateUntil
       recursiveUpdate matchAttrs overrideExisting getOutput getBin
       getLib getDev getMan chooseDevOutputs zipWithNames zip
-      recurseIntoAttrs dontRecurseIntoAttrs;
+      recurseIntoAttrs dontRecurseIntoAttrs cartesianProductOfSets;
     inherit (self.lists) singleton forEach foldr fold foldl foldl' imap0 imap1
       concatMap flatten remove findSingle findFirst any all count
       optional optionals toList range partition zipListsWith zipLists
diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix
index 35a5801c724..0d249968402 100644
--- a/lib/tests/misc.nix
+++ b/lib/tests/misc.nix
@@ -660,4 +660,71 @@ runTests {
     expected = [ [ "foo" ] [ "foo" "<name>" "bar" ] [ "foo" "bar" ] ];
   };
 
+  testCartesianProductOfEmptySet = {
+    expr = cartesianProductOfSets {};
+    expected = [ {} ];
+  };
+
+  testCartesianProductOfOneSet = {
+    expr = cartesianProductOfSets { a = [ 1 2 3 ]; };
+    expected = [ { a = 1; } { a = 2; } { a = 3; } ];
+  };
+
+  testCartesianProductOfTwoSets = {
+    expr = cartesianProductOfSets { a = [ 1 ]; b = [ 10 20 ]; };
+    expected = [
+      { a = 1; b = 10; }
+      { a = 1; b = 20; }
+    ];
+  };
+
+  testCartesianProductOfTwoSetsWithOneEmpty = {
+    expr = cartesianProductOfSets { a = [ ]; b = [ 10 20 ]; };
+    expected = [ ];
+  };
+
+  testCartesianProductOfThreeSets = {
+    expr = cartesianProductOfSets {
+      a = [   1   2   3 ];
+      b = [  10  20  30 ];
+      c = [ 100 200 300 ];
+    };
+    expected = [
+      { a = 1; b = 10; c = 100; }
+      { a = 1; b = 10; c = 200; }
+      { a = 1; b = 10; c = 300; }
+
+      { a = 1; b = 20; c = 100; }
+      { a = 1; b = 20; c = 200; }
+      { a = 1; b = 20; c = 300; }
+
+      { a = 1; b = 30; c = 100; }
+      { a = 1; b = 30; c = 200; }
+      { a = 1; b = 30; c = 300; }
+
+      { a = 2; b = 10; c = 100; }
+      { a = 2; b = 10; c = 200; }
+      { a = 2; b = 10; c = 300; }
+
+      { a = 2; b = 20; c = 100; }
+      { a = 2; b = 20; c = 200; }
+      { a = 2; b = 20; c = 300; }
+
+      { a = 2; b = 30; c = 100; }
+      { a = 2; b = 30; c = 200; }
+      { a = 2; b = 30; c = 300; }
+
+      { a = 3; b = 10; c = 100; }
+      { a = 3; b = 10; c = 200; }
+      { a = 3; b = 10; c = 300; }
+
+      { a = 3; b = 20; c = 100; }
+      { a = 3; b = 20; c = 200; }
+      { a = 3; b = 20; c = 300; }
+
+      { a = 3; b = 30; c = 100; }
+      { a = 3; b = 30; c = 200; }
+      { a = 3; b = 30; c = 300; }
+    ];
+  };
 }