From ed64a44b827282862042b9a032d83205b740f4d0 Mon Sep 17 00:00:00 2001 From: mike <98623181+1Kinoti@users.noreply.github.com> Date: Wed, 19 Apr 2023 20:09:10 +0300 Subject: [PATCH] add `filter-map` command to `std iter` (#8926) # Description as title says --- crates/nu-std/lib/iter.nu | 70 ++++++++++++++++++-------------- crates/nu-std/tests/test_iter.nu | 11 +++++ 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/crates/nu-std/lib/iter.nu b/crates/nu-std/lib/iter.nu index f15c5f8c0f..24a0952056 100644 --- a/crates/nu-std/lib/iter.nu +++ b/crates/nu-std/lib/iter.nu @@ -28,11 +28,10 @@ # assert equal $not_found null # ``` export def "iter find" [ # -> any | null - predicate: closure # the closure used to perform the search + fn: closure # the closure used to perform the search ] { - let list = (self collect) try { - $list | filter $predicate | get 0? + filter $fn | get 0? } catch { null } @@ -51,21 +50,12 @@ export def "iter find" [ # -> any | null export def "iter intersperse" [ # -> list separator: any, # the separator to be used ] { - let list = (self collect) - - let len = ($list | length); - if ($list | is-empty) { - return $list - } - - $list - | enumerate - | reduce -f [] {|it, acc| - if ($it.index == $len - 1) { - $acc ++ [$it.item] - } else { - $acc ++ [$it.item, $separator] - } + reduce -f [] {|it, acc| + $acc ++ [$it, $separator] + } + | match $in { + [] => [], + $xs => ($xs | take (($xs | length) - 1 )) } } @@ -90,24 +80,42 @@ export def "iter intersperse" [ # -> list # ``` export def "iter scan" [ # -> list init: any # initial value to seed the initial state - f: closure # the closure to perform the scan + fn: closure # the closure to perform the scan --noinit(-n) # remove the initial value from the result ] { - let res = (reduce -f [$init] {|it, acc| - $acc ++ [(do $f ($acc | last) $it)] - }) - - if $noinit { - $res | skip + reduce -f [$init] {|it, acc| + $acc ++ [(do $fn ($acc | last) $it)] + } + | if $noinit { + $in | skip } else { - $res + $in } } -# Accepts inputs from a pipeline and builds a list for the `iter *` -# commands to work with -def "self collect" [] { # -> list - reduce -f [] {|it, acc| - $acc ++ $it +# Returns a list of values for which the supplied closure does not +# return `null` or an error. It is equivalent to +# `$in | each $fn | filter $fn` +# +# # Example +# ```nu +# use std ["assert equal" "iter filter-map"] +# +# let res = ([2 5 "4" 7] | iter filter-map {|it| $it ** 2}) +# +# assert equal $res [4 25 49] +# ``` +export def "iter filter-map" [ # -> list + fn: closure # the closure to apply to the input +] { + each {|$it| + try { + do $fn $it + } catch { + null + } + } + | filter {|it| + $it != null } } diff --git a/crates/nu-std/tests/test_iter.nu b/crates/nu-std/tests/test_iter.nu index b5291192c5..10cb1597f7 100644 --- a/crates/nu-std/tests/test_iter.nu +++ b/crates/nu-std/tests/test_iter.nu @@ -48,3 +48,14 @@ export def test_iter_scan [] { let scanned = ([a b c d] | iter scan "" {|x, y| [$x, $y] | str join} -n) assert equal $scanned ["a" "ab" "abc" "abcd"] } + +export def test_iter_filter_map [] { + let res = ([2 5 "4" 7] | iter filter-map {|it| $it ** 2}) + assert equal $res [4 25 49] + + let res = ( + ["3" "42" "69" "n" "x" ""] + | iter filter-map {|it| $it | into int} + ) + assert equal $res [3 42 69] +}