mirror of
https://github.com/nushell/nushell.git
synced 2024-11-29 03:44:19 +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 *
|
use dirs *
|
||||||
}
|
}
|
||||||
export use help *
|
export use help *
|
||||||
|
export use iter *
|
||||||
export use log *
|
export use log *
|
||||||
export use testing *
|
export use testing *
|
||||||
export use xml *
|
export use xml *
|
||||||
|
@ -74,6 +74,7 @@ pub fn load_standard_library(
|
|||||||
|
|
||||||
// the rest of the library
|
// the rest of the library
|
||||||
("dirs", include_str!("../lib/dirs.nu")),
|
("dirs", include_str!("../lib/dirs.nu")),
|
||||||
|
("iter", include_str!("../lib/iter.nu")),
|
||||||
("help", include_str!("../lib/help.nu")),
|
("help", include_str!("../lib/help.nu")),
|
||||||
("testing", include_str!("../lib/testing.nu")),
|
("testing", include_str!("../lib/testing.nu")),
|
||||||
("xml", include_str!("../lib/xml.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