about summary refs log tree commit diff
path: root/lib/lists.nix
diff options
context:
space:
mode:
authorSilvan Mosberger <silvan.mosberger@tweag.io>2023-07-14 19:26:08 +0200
committerSilvan Mosberger <silvan.mosberger@tweag.io>2023-07-20 22:42:01 +0200
commit7f61b01600ecbdaa2a57c51097f2ece9e421c4fe (patch)
tree4b18b3b06cb8f0771688757af353b45b56b0dbef /lib/lists.nix
parent53dcfd24ad71bb1a26c9d17cbd2af1f83a2da7a3 (diff)
lib.lists.commonPrefix: init
Diffstat (limited to 'lib/lists.nix')
-rw-r--r--lib/lists.nix28
1 files changed, 27 insertions, 1 deletions
diff --git a/lib/lists.nix b/lib/lists.nix
index c3e889644b3ed..3e058b3f1aef1 100644
--- a/lib/lists.nix
+++ b/lib/lists.nix
@@ -3,7 +3,7 @@
 { lib }:
 let
   inherit (lib.strings) toInt;
-  inherit (lib.trivial) compare min;
+  inherit (lib.trivial) compare min id;
   inherit (lib.attrsets) mapAttrs;
 in
 rec {
@@ -663,6 +663,32 @@ rec {
        else if start + count > len then len - start
        else count);
 
+  /* The common prefix of two lists.
+
+  Type: commonPrefix :: [a] -> [a] -> [a]
+
+  Example:
+    commonPrefix [ 1 2 3 4 5 6 ] [ 1 2 4 8 ]
+    => [ 1 2 ]
+    commonPrefix [ 1 2 3 ] [ 1 2 3 4 5 ]
+    => [ 1 2 3 ]
+    commonPrefix [ 1 2 3 ] [ 4 5 6 ]
+    => [ ]
+  */
+  commonPrefix =
+    list1:
+    list2:
+    let
+      # Zip the lists together into a list of booleans whether each element matches
+      matchings = zipListsWith (fst: snd: fst != snd) list1 list2;
+      # Find the first index where the elements don't match,
+      # which will then also be the length of the common prefix.
+      # If all elements match, we fall back to the length of the zipped list,
+      # which is the same as the length of the smaller list.
+      commonPrefixLength = findFirstIndex id (length matchings) matchings;
+    in
+    take commonPrefixLength list1;
+
   /* Return the last element of a list.
 
      This function throws an error if the list is empty.