mirror of
https://github.com/nushell/nushell.git
synced 2024-11-28 19:33:47 +01:00
add iter
module to standard library (#8899)
# Description this pr introduces an `iter` module to the standard library. the module is aimed at extending the filter commands.
This commit is contained in:
parent
29256b161c
commit
91c01bf6b3
113
crates/nu-std/lib/iter.nu
Normal file
113
crates/nu-std/lib/iter.nu
Normal file
@ -0,0 +1,113 @@
|
||||
# | Filter Extensions
|
||||
#
|
||||
# This module implements extensions to the `filters` commands
|
||||
#
|
||||
# They are prefixed with `iter` so as to avoid conflicts with
|
||||
# the inbuilt filters
|
||||
|
||||
# Returns the first element of the list that matches the
|
||||
# closure predicate, `null` otherwise
|
||||
#
|
||||
# # Invariant
|
||||
# > The closure has to be a predicate (returning a bool value)
|
||||
# > else `null` is returned
|
||||
# > The closure also has to be valid for the types it receives
|
||||
# > These will be flagged as errors later as closure annotations
|
||||
# > are implemented
|
||||
#
|
||||
# # Example
|
||||
# ```
|
||||
# use std ["assert equal" "iter find"]
|
||||
#
|
||||
# let haystack = ["shell", "abc", "around", "nushell", "std"]
|
||||
#
|
||||
# let found = ($haystack | iter find {|it| $it starts-with "a" })
|
||||
# let not_found = ($haystack | iter find {|it| $it mod 2 == 0})
|
||||
#
|
||||
# assert equal $found "abc"
|
||||
# assert equal $not_found null
|
||||
# ```
|
||||
export def "iter find" [ # -> any | null
|
||||
predicate: closure # the closure used to perform the search
|
||||
] {
|
||||
let list = (self collect)
|
||||
try {
|
||||
$list | filter $predicate | get 0?
|
||||
} catch {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
# Returns a new list with the separator between adjacent
|
||||
# items of the original list
|
||||
#
|
||||
# # Example
|
||||
# ```
|
||||
# use std ["assert equal" "iter intersperse"]
|
||||
#
|
||||
# let res = ([1 2 3 4] | iter intersperse 0)
|
||||
# assert equal $res [1 0 2 0 3 0 4]
|
||||
# ```
|
||||
export def "iter intersperse" [ # -> list<any>
|
||||
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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Returns a list of intermediate steps performed by `reduce`
|
||||
# (`fold`). It takes two arguments, an initial value to seed the
|
||||
# initial state and a closure that takes two arguments, the first
|
||||
# being the internal state and the second the list element in the
|
||||
# current iteration.
|
||||
#
|
||||
# # Example
|
||||
# ```
|
||||
# use std ["assert equal" "iter scan"]
|
||||
# let scanned = ([1 2 3] | iter scan 0 {|x, y| $x + $y})
|
||||
#
|
||||
# assert equal $scanned [0, 1, 3, 6]
|
||||
#
|
||||
# # use the --noinit(-n) flag to remove the initial value from
|
||||
# # the final result
|
||||
# let scanned = ([1 2 3] | iter scan 0 {|x, y| $x + $y} -n)
|
||||
#
|
||||
# assert equal $scanned [1, 3, 6]
|
||||
# ```
|
||||
export def "iter scan" [ # -> list<any>
|
||||
init: any # initial value to seed the initial state
|
||||
f: 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
|
||||
} else {
|
||||
$res
|
||||
}
|
||||
}
|
||||
|
||||
# Accepts inputs from a pipeline and builds a list for the `iter *`
|
||||
# commands to work with
|
||||
def "self collect" [] { # -> list<any>
|
||||
reduce -f [] {|it, acc|
|
||||
$acc ++ $it
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ export-env {
|
||||
use dirs *
|
||||
}
|
||||
export use help *
|
||||
export use iter *
|
||||
export use log *
|
||||
export use testing *
|
||||
export use xml *
|
||||
|
@ -74,6 +74,7 @@ pub fn load_standard_library(
|
||||
|
||||
// the rest of the library
|
||||
("dirs", include_str!("../lib/dirs.nu")),
|
||||
("iter", include_str!("../lib/iter.nu")),
|
||||
("help", include_str!("../lib/help.nu")),
|
||||
("testing", include_str!("../lib/testing.nu")),
|
||||
("xml", include_str!("../lib/xml.nu")),
|
||||
|
50
crates/nu-std/tests/test_iter.nu
Normal file
50
crates/nu-std/tests/test_iter.nu
Normal file
@ -0,0 +1,50 @@
|
||||
use std *
|
||||
|
||||
export def test_iter_find [] {
|
||||
let hastack1 = [1 2 3 4 5 6 7]
|
||||
let hastack2 = [nushell rust shell iter std]
|
||||
let hastack3 = [nu 69 2023-04-20 "std"]
|
||||
|
||||
let res = ($hastack1 | iter find {|it| $it mod 2 == 0})
|
||||
assert equal $res 2
|
||||
|
||||
let res = ($hastack2 | iter find {|it| $it starts-with 's'})
|
||||
assert equal $res 'shell'
|
||||
|
||||
let res = ($hastack2 | iter find {|it| ($it | length) == 50})
|
||||
assert equal $res null
|
||||
|
||||
let res = ($hastack3 | iter find {|it| (it | describe) == filesize})
|
||||
assert equal $res null
|
||||
}
|
||||
|
||||
export def test_iter_intersperse [] {
|
||||
let res = ([1 2 3 4] | iter intersperse 0)
|
||||
assert equal $res [1 0 2 0 3 0 4]
|
||||
|
||||
let res = ([] | iter intersperse x)
|
||||
assert equal $res []
|
||||
|
||||
let res = ([1] | iter intersperse 5)
|
||||
assert equal $res [1]
|
||||
|
||||
let res = ([a b c d e] | iter intersperse 5)
|
||||
assert equal $res [a 5 b 5 c 5 d 5 e]
|
||||
|
||||
let res = (1..4 | iter intersperse 0)
|
||||
assert equal $res [1 0 2 0 3 0 4]
|
||||
|
||||
let res = (4 | iter intersperse 1)
|
||||
assert equal $res [4]
|
||||
}
|
||||
|
||||
export def test_iter_scan [] {
|
||||
let scanned = ([1 2 3] | iter scan 0 {|x, y| $x + $y} -n)
|
||||
assert equal $scanned [1, 3, 6]
|
||||
|
||||
let scanned = ([1 2 3] | iter scan 0 {|x, y| $x + $y})
|
||||
assert equal $scanned [0, 1, 3, 6]
|
||||
|
||||
let scanned = ([a b c d] | iter scan "" {|x, y| [$x, $y] | str join} -n)
|
||||
assert equal $scanned ["a" "ab" "abc" "abcd"]
|
||||
}
|
Loading…
Reference in New Issue
Block a user