From 4e85c4ff277c883edf67d87d5d7d158a49dc4850 Mon Sep 17 00:00:00 2001 From: volth Date: Sun, 10 Jun 2018 17:31:09 +0000 Subject: [PATCH] lib: add groupBy (#38612) --- lib/default.nix | 2 +- lib/lists.nix | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/lib/default.nix b/lib/default.nix index 4ca2e2ea6e3..aca484d9a8e 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -76,7 +76,7 @@ let optional optionals toList range partition zipListsWith zipLists reverseList listDfs toposort sort naturalSort compareLists take drop sublist last init crossLists unique intersectLists - subtractLists mutuallyExclusive; + subtractLists mutuallyExclusive groupBy groupBy'; inherit (strings) concatStrings concatMapStrings concatImapStrings intersperse concatStringsSep concatMapStringsSep concatImapStringsSep makeSearchPath makeSearchPathOutput diff --git a/lib/lists.nix b/lib/lists.nix index 5ec97f5a07f..194e1c200ec 100644 --- a/lib/lists.nix +++ b/lib/lists.nix @@ -250,6 +250,42 @@ rec { else { right = t.right; wrong = [h] ++ t.wrong; } ) { right = []; wrong = []; }); + /* Splits the elements of a list into many lists, using the return value of a predicate. + Predicate should return a string which becomes keys of attrset `groupBy' returns. + + `groupBy'' allows to customise the combining function and initial value + + Example: + groupBy (x: boolToString (x > 2)) [ 5 1 2 3 4 ] + => { true = [ 5 3 4 ]; false = [ 1 2 ]; } + groupBy (x: x.name) [ {name = "icewm"; script = "icewm &";} + {name = "xfce"; script = "xfce4-session &";} + {name = "icewm"; script = "icewmbg &";} + {name = "mate"; script = "gnome-session &";} + ] + => { icewm = [ { name = "icewm"; script = "icewm &"; } + { name = "icewm"; script = "icewmbg &"; } ]; + mate = [ { name = "mate"; script = "gnome-session &"; } ]; + xfce = [ { name = "xfce"; script = "xfce4-session &"; } ]; + } + + + groupBy' allows to customise the combining function and initial value + + Example: + groupBy' builtins.add 0 (x: boolToString (x > 2)) [ 5 1 2 3 4 ] + => { true = 12; false = 3; } + */ + groupBy' = op: nul: pred: lst: + foldl' (r: e: + let + key = pred e; + in + r // { ${key} = op (r.${key} or nul) e; } + ) {} lst; + + groupBy = groupBy' (sum: e: sum ++ [e]) []; + /* Merges two lists of the same size together. If the sizes aren't the same the merging stops at the shortest. How both lists are merged is defined by the first argument.