lib.lists.findFirstIndex: init

Co-authored-by: Robert Hensing <roberth@users.noreply.github.com>
This commit is contained in:
Silvan Mosberger
2023-07-19 16:44:11 +02:00
parent a4f7840e18
commit 53dcfd24ad
2 changed files with 64 additions and 28 deletions

View File

@@ -180,18 +180,18 @@ rec {
else if len != 1 then multiple else if len != 1 then multiple
else head found; else head found;
/* Find the first element in the list matching the specified /* Find the first index in the list matching the specified
predicate or return `default` if no such element exists. predicate or return `default` if no such element exists.
Type: findFirst :: (a -> bool) -> a -> [a] -> a Type: findFirstIndex :: (a -> Bool) -> b -> [a] -> (Int | b)
Example: Example:
findFirst (x: x > 3) 7 [ 1 6 4 ] findFirstIndex (x: x > 3) null [ 0 6 4 ]
=> 6 => 1
findFirst (x: x > 9) 7 [ 1 6 4 ] findFirstIndex (x: x > 9) null [ 0 6 4 ]
=> 7 => null
*/ */
findFirst = findFirstIndex =
# Predicate # Predicate
pred: pred:
# Default value to return # Default value to return
@@ -229,7 +229,33 @@ rec {
if resultIndex < 0 then if resultIndex < 0 then
default default
else else
elemAt list resultIndex; resultIndex;
/* Find the first element in the list matching the specified
predicate or return `default` if no such element exists.
Type: findFirst :: (a -> bool) -> a -> [a] -> a
Example:
findFirst (x: x > 3) 7 [ 1 6 4 ]
=> 6
findFirst (x: x > 9) 7 [ 1 6 4 ]
=> 7
*/
findFirst =
# Predicate
pred:
# Default value to return
default:
# Input list
list:
let
index = findFirstIndex pred null list;
in
if index == null then
default
else
elemAt list index;
/* Return true if function `pred` returns true for at least one /* Return true if function `pred` returns true for at least one
element of `list`. element of `list`.

View File

@@ -518,45 +518,55 @@ runTests {
expected = false; expected = false;
}; };
testFindFirstExample1 = { testFindFirstIndexExample1 = {
expr = findFirst (x: x > 3) 7 [ 1 6 4 ]; expr = lists.findFirstIndex (x: x > 3) (abort "index found, so a default must not be evaluated") [ 1 6 4 ];
expected = 6; expected = 1;
}; };
testFindFirstExample2 = { testFindFirstIndexExample2 = {
expr = findFirst (x: x > 9) 7 [ 1 6 4 ]; expr = lists.findFirstIndex (x: x > 9) "a very specific default" [ 1 6 4 ];
expected = 7; expected = "a very specific default";
}; };
testFindFirstEmpty = { testFindFirstIndexEmpty = {
expr = findFirst (abort "when the list is empty, the predicate is not needed") null []; expr = lists.findFirstIndex (abort "when the list is empty, the predicate is not needed") null [];
expected = null; expected = null;
}; };
testFindFirstSingleMatch = { testFindFirstIndexSingleMatch = {
expr = findFirst (x: x == 5) null [ 5 ]; expr = lists.findFirstIndex (x: x == 5) null [ 5 ];
expected = 5; expected = 0;
}; };
testFindFirstSingleDefault = { testFindFirstIndexSingleDefault = {
expr = findFirst (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ]; expr = lists.findFirstIndex (x: false) null [ (abort "if the predicate doesn't access the value, it must not be evaluated") ];
expected = null; expected = null;
}; };
testFindFirstNone = { testFindFirstIndexNone = {
expr = builtins.tryEval (findFirst (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]); expr = builtins.tryEval (lists.findFirstIndex (x: x == 2) null [ 1 (throw "the last element must be evaluated when there's no match") ]);
expected = { success = false; value = false; }; expected = { success = false; value = false; };
}; };
# Makes sure that the implementation doesn't cause a stack overflow # Makes sure that the implementation doesn't cause a stack overflow
testFindFirstBig = { testFindFirstIndexBig = {
expr = findFirst (x: x == 1000000) null (range 0 1000000); expr = lists.findFirstIndex (x: x == 1000000) null (range 0 1000000);
expected = 1000000; expected = 1000000;
}; };
testFindFirstLazy = { testFindFirstIndexLazy = {
expr = findFirst (x: x == 1) 7 [ 1 (abort "list elements after the match must not be evaluated") ]; expr = lists.findFirstIndex (x: x == 1) null [ 1 (abort "list elements after the match must not be evaluated") ];
expected = 1; expected = 0;
};
testFindFirstExample1 = {
expr = lists.findFirst (x: x > 3) 7 [ 1 6 4 ];
expected = 6;
};
testFindFirstExample2 = {
expr = lists.findFirst (x: x > 9) 7 [ 1 6 4 ];
expected = 7;
}; };
# ATTRSETS # ATTRSETS