Unverified Commit 24af4c04 authored by Silvan Mosberger's avatar Silvan Mosberger Committed by GitHub
Browse files

Merge pull request #214021 from tweag/ifilter0

lib.lists.ifilter0: init
parents e41ca779 6861ef77
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ let
      recurseIntoAttrs dontRecurseIntoAttrs cartesianProduct cartesianProductOfSets
      mapCartesianProduct updateManyAttrsByPath;
    inherit (self.lists) singleton forEach foldr fold foldl foldl' imap0 imap1
      concatMap flatten remove findSingle findFirst any all count
      ifilter0 concatMap flatten remove findSingle findFirst any all count
      optional optionals toList range replicate partition zipListsWith zipLists
      reverseList listDfs toposort sort sortOn naturalSort compareLists take
      drop sublist last init crossLists unique allUnique intersectLists
+49 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
{ lib }:
let
  inherit (lib.strings) toInt;
  inherit (lib.trivial) compare min id warn;
  inherit (lib.trivial) compare min id warn pipe;
  inherit (lib.attrsets) mapAttrs;
in
rec {
@@ -333,6 +333,54 @@ rec {
  */
  imap1 = f: list: genList (n: f (n + 1) (elemAt list n)) (length list);

  /**
    Filter a list for elements that satisfy a predicate function.
    The predicate function is called with both the index and value for each element.
    It must return `true`/`false` to include/exclude a given element in the result.
    This function is strict in the result of the predicate function for each element.
    This function has O(n) complexity.

    Also see [`builtins.filter`](https://nixos.org/manual/nix/stable/language/builtins.html#builtins-filter) (available as `lib.lists.filter`),
    which can be used instead when the index isn't needed.

    # Inputs

    `ipred`

    : The predicate function, it takes two arguments:
      - 1. (int): the index of the element.
      - 2. (a): the value of the element.

      It must return `true`/`false` to include/exclude a given element from the result.

    `list`

    : The list to filter using the predicate.

    # Type
    ```
    ifilter0 :: (int -> a -> bool) -> [a] -> [a]
    ```

    # Examples
    :::{.example}
    ## `lib.lists.ifilter0` usage example

    ```nix
    ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ]
    => [ 1 3 ]
    ```
    :::
  */
  ifilter0 =
    ipred:
    input:
    map (idx: elemAt input idx) (
      filter (idx: ipred idx (elemAt input idx)) (
        genList (x: x) (length input)
      )
    );

  /**
    Map and concatenate the result.

+27 −0
Original line number Diff line number Diff line
@@ -63,8 +63,10 @@ let
    hasAttrByPath
    hasInfix
    id
    ifilter0
    isStorePath
    lazyDerivation
    length
    lists
    listToAttrs
    makeExtensible
@@ -651,6 +653,31 @@ runTests {
    expected = ["b" "c"];
  };

  testIfilter0Example = {
    expr = ifilter0 (i: v: i == 0 || v > 2) [ 1 2 3 ];
    expected = [ 1 3 ];
  };
  testIfilter0Empty = {
    expr = ifilter0 (i: v: abort "shouldn't be evaluated!") [ ];
    expected = [ ];
  };
  testIfilter0IndexOnly = {
    expr = length (ifilter0 (i: v: mod i 2 == 0) [ (throw "0") (throw "1") (throw "2") (throw "3")]);
    expected = 2;
  };
  testIfilter0All = {
    expr = ifilter0 (i: v: true) [ 10 11 12 13 14 15 ];
    expected = [ 10 11 12 13 14 15 ];
  };
  testIfilter0First = {
    expr = ifilter0 (i: v: i == 0) [ 10 11 12 13 14 15 ];
    expected = [ 10 ];
  };
  testIfilter0Last = {
    expr = ifilter0 (i: v: i == 5) [ 10 11 12 13 14 15 ];
    expected = [ 15 ];
  };

  testFold =
    let
      f = op: fold: fold op 0 (range 0 100);