summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/lib/attrsets.nix13
-rw-r--r--pkgs/lib/tests.nix7
2 files changed, 19 insertions, 1 deletions
diff --git a/pkgs/lib/attrsets.nix b/pkgs/lib/attrsets.nix
index de6eccbec1f..63448847a15 100644
--- a/pkgs/lib/attrsets.nix
+++ b/pkgs/lib/attrsets.nix
@@ -5,7 +5,8 @@ with {
   inherit (import ./trivial.nix) or;
   inherit (import ./default.nix) fold;
   inherit (import ./strings.nix) concatStringsSep;
-  inherit (import ./lists.nix) concatMap concatLists;
+  inherit (import ./lists.nix) concatMap concatLists all;
+  inherit (import ./misc.nix) maybeAttr;
 };
 
 rec {
@@ -78,6 +79,16 @@ rec {
   filterAttrs = pred: set:
     listToAttrs (fold (n: ys: let v = getAttr n set; in if pred n v then [(nameValuePair n v)] ++ ys else ys) [] (attrNames set));
 
+  /* foldAttrs: apply fold functions to values grouped by key. Eg accumulate values as list:
+     foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }]
+     => { a = [ 2 3 ]; }
+  */
+  foldAttrs = op: nul: list_of_attrs:
+    fold (n: a:
+        fold (name: o:
+          o // (listToAttrs [{inherit name; value = op (getAttr name n) (maybeAttr name nul a); }])
+        ) a (attrNames n)
+    ) {} list_of_attrs;
 
   /* Recursively collect sets that verify a given predicate named `pred'
      from the set `attrs'.  The recursion is stopped when the predicate is
diff --git a/pkgs/lib/tests.nix b/pkgs/lib/tests.nix
index 835298ddb9e..04acb7632ea 100644
--- a/pkgs/lib/tests.nix
+++ b/pkgs/lib/tests.nix
@@ -58,6 +58,13 @@ runTests {
     ([ 1 2 3 ] == (take 4 [  1 2 3 ]))
   ];
 
+  testFoldAttrs = {
+    expr = foldAttrs (n: a: [n] ++ a) [] [
+    { a = 2; b = 7; }
+    { a = 3;        c = 8; }
+    ];
+    expected = { a = [ 2 3 ]; b = [7]; c = [8];};
+  };
 
   testOverridableDelayableArgsTest = {
     expr =