New built function: filter
da-tubi opened this issue · comments
How about add a new built-in filter
:
fn filter {|pred @rest|
each {|x|
if ($pred $x) {
put $x
}
} $@rest
}
If so, I would like an option ¬
to invert the sense of the test. And perhaps even an option &out
(defaulting to $put~
) to specify an output function.
Here is my current filter function:
fn filter {|pred~ @items ¬=$false &out=$put~|
var ck~ = $pred~
if $not { set ck~ = {|item| not (pred $item)} }
each {|item| if (ck $item) { $out $item }} $@items
}
Here is the scala code snippet of filter and filterNot:
scala> Seq(1, 2, 3).filter(x => x % 2 == 0)
res0: Seq[Int] = List(2)
scala> Seq(1, 2, 3).filterNot(x => x % 2 == 0)
res2: Seq[Int] = List(1, 3)
I would like an option ¬ to invert the sense of the test.
I think you're better off using composable functions instead:
fn fnot {|f| put {|@args| not ($f $@args) }}
fn even {|n| == (% $n 2) 0 }
range 5 | filter (fnot $even~)
▶ (num 1)
▶ (num 3)
Even better, define a comp
function:
fn even {|n| == (% $n 2) 0 }
range 5 | filter (fn:comp $not~ $even~)
▶ (num 1)
▶ (num 3)
And perhaps even an option &out (defaulting to $put~) to specify an output function.
I think this breaks the pipeline nature of the shell. Again, you can compose things so nicely with pipes:
fn even {|n| == (% $n 2) 0 }
fn exclaim {|s| put $s! }
range 5 | filter (fn:comp $not~ $even~) | each $exclaim~
▶ 1!
▶ 3!
I have had a filter
command in my Elvish config for a long time (see https://github.com/krader1961/elvish-lib/):
# Filters a sequence of items and outputs those for whom the function outputs
# $true.
fn filter {|&out=$false func~ @inputs|
if $out {
each {|item| if (not (func $item)) { put $item } } $@inputs
} else {
each {|item| if (func $item) { put $item } } $@inputs
}
}
This arguably should be a builtin but only if doing so improves the performance.