lib/attrsets: add cartesianProductOfSets function

This commit is contained in:
Jacek Galowicz 2021-01-25 16:59:46 +01:00
parent d9353519d7
commit 123045a570
4 changed files with 125 additions and 2 deletions

View file

@ -1711,4 +1711,43 @@ recursiveUpdate
</example>
</section>
<section xml:id="function-library-lib.attrsets.cartesianProductOfSets">
<title><function>lib.attrsets.cartesianProductOfSets</function></title>
<subtitle><literal>cartesianProductOfSets :: AttrSet -> [ AttrSet ]</literal>
</subtitle>
<xi:include href="./locations.xml" xpointer="lib.attrsets.cartesianProductOfSets" />
<para>
Return the cartesian product of attribute set value combinations.
</para>
<variablelist>
<varlistentry>
<term>
<varname>set</varname>
</term>
<listitem>
<para>
An attribute set with attributes that carry lists of values.
</para>
</listitem>
</varlistentry>
</variablelist>
<example xml:id="function-library-lib.attrsets.cartesianProductOfSets-example">
<title>Creating the cartesian product of a list of attribute values</title>
<programlisting><![CDATA[
cartesianProductOfSets { a = [ 1 2 ]; b = [ 10 20 ]; }
=> [
{ a = 1; b = 10; }
{ a = 1; b = 20; }
{ a = 2; b = 10; }
{ a = 2; b = 20; }
]
]]></programlisting>
</example>
</section>
</section>

View file

@ -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;
}

View file

@ -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

View file

@ -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; }
];
};
}