summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--lib/default.nix2
-rw-r--r--lib/lists.nix23
2 files changed, 23 insertions, 2 deletions
diff --git a/lib/default.nix b/lib/default.nix
index 59b3d2159daa..c292ed33e1da 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -74,7 +74,7 @@ let
     inherit (lists) singleton foldr fold foldl foldl' imap0 imap1
       concatMap flatten remove findSingle findFirst any all count
       optional optionals toList range partition zipListsWith zipLists
-      reverseList listDfs toposort sort compareLists take drop sublist
+      reverseList listDfs toposort sort naturalSort compareLists take drop sublist
       last init crossLists unique intersectLists subtractLists
       mutuallyExclusive;
     inherit (strings) concatStrings concatMapStrings concatImapStrings
diff --git a/lib/lists.nix b/lib/lists.nix
index 424d2c57f556..5ec97f5a07f3 100644
--- a/lib/lists.nix
+++ b/lib/lists.nix
@@ -1,7 +1,9 @@
 # General list operations.
 { lib }:
 with lib.trivial;
-
+let
+  inherit (lib.strings) toInt;
+in
 rec {
 
   inherit (builtins) head tail length isList elemAt concatLists filter elem genList;
@@ -409,6 +411,25 @@ rec {
               then compareLists cmp (tail a) (tail b)
               else rel;
 
+  /* Sort list using "Natural sorting".
+     Numeric portions of strings are sorted in numeric order.
+
+     Example:
+       naturalSort ["disk11" "disk8" "disk100" "disk9"]
+       => ["disk8" "disk9" "disk11" "disk100"]
+       naturalSort ["10.46.133.149" "10.5.16.62" "10.54.16.25"]
+       => ["10.5.16.62" "10.46.133.149" "10.54.16.25"]
+       naturalSort ["v0.2" "v0.15" "v0.0.9"]
+       => [ "v0.0.9" "v0.2" "v0.15" ]
+  */
+  naturalSort = lst:
+    let
+      vectorise = s: map (x: if isList x then toInt (head x) else x) (builtins.split "(0|[1-9][0-9]*)" s);
+      prepared = map (x: [ (vectorise x) x ]) lst; # remember vectorised version for O(n) regex splits
+      less = a: b: (compareLists compare (head a) (head b)) < 0;
+    in
+      map (x: elemAt x 1) (sort less prepared);
+
   /* Return the first (at most) N elements of a list.
 
      Example: