elv-lib/mods/list.elv

179 lines
3.0 KiB
Plaintext

use ./common
use ./num
var -l~ = $common:to-list~
var -c~ = $common:cexec~
var '++~' = $'num:++~'
var is-neg~ = $num:is-neg~
fn indexes {|&from=0 &step=1 @argv|
var c = (count (-l $@argv))
var from = (-c (is-neg $from) (+ $from $c) $from)
var to = (-c (is-neg $step) -1 $c)
if (and (>= $from 0) (< $from $c)) {
range &step=$step $from $to
}
}
fn loop {|&from=0 &step=1 @argv|
var l = (-l $@argv)
indexes &from=$from &step=$step $l | each {|i|
put [ $i $l[$i] ]
}
}
fn foreach {|&from=0 &step=1 &end=$false cb @argv|
if (not $end) {
loop &from=$from &step=$step $@argv | each {|e| $cb $@e}
} else {
loop &from=$from &step=$step $@argv | each {|e|
if ($end $@e) {
break
}
$cb $@e
}
}
}
fn pforeach {|&from=0 &step=1 cb @argv|
loop &from=$from &step=$step $@argv | peach {|e| $cb $@e}
}
fn reach {|cb @argv|
foreach &from=-1 &step=-1 {|_ e| $cb $e} $@argv
}
fn reverse {|@argv|
reach $put~ $@argv
}
fn is-empty {|@argv|
num:is-zero (count (-l $@argv))
}
fn is-not-empty {|@argv|
not (is-empty $@argv)
}
fn filter {|cb @argv|
each {|e|
-c ($cb $e) $e $nop~
} (-l $@argv)
}
fn filter-not {|cb @argv|
filter {|v| not ($cb $v)} $@argv
}
fn contains {|cb @argv|
var cb2~ = (common:cond (eq (kind-of $cb) fn) $cb {|e| eq $cb $e})
each {|e|
if (cb2 $e) {
put $true
return
}
} (-l $@argv)
put $false
}
fn contains-not {|cb @argv|
not (contains $cb $@argv)
}
fn search {|cb @argv|
foreach {|i e|
-c ($cb $i $e) [$i $e] $nop~
} $@argv
}
fn search-not {|cb @argv|
search {|i e| not ($cb $i $e) } $@argv
}
fn exists {|cb @argv|
var r = $false
foreach {|i e|
if ($cb $i $e) {
set r = $true
break
}
} $@argv
put $r
}
fn exists-not {|cb @argv|
not (exists $cb $@argv)
}
fn search-first {|&from=$nil &reverse=$false cb @argv|
var step = (-c $reverse -1 1)
if (not $from) {
set from = (-c $reverse -1 0)
}
foreach &from=$from &step=$step {|i e|
if ($cb $i $e) {
put [$i $e]
break
}
} $@argv
}
fn first {|&from=$nil &reverse=$false cb @argv|
search-first &from=$from &reverse=$reverse {|_ e| $cb $e} $@argv | each {|e|
put $e[1]
break
}
}
fn reduce {|acc cb @argv|
each {|e|
set acc = ($cb $acc $e)
} (-l $@argv)
put $acc
}
fn remove-duplicate {|@argv|
var done = [&]
each {|e|
if (not (has-key $done $e)) {
set done[$e] = $nil
put $e
}
} (-l $@argv)
}
fn swap {|i j @argv|
var l = (-l $@argv)
var c = (count $l)
if (< $i 0) {
set i = (+ $i $c)
}
if (< $j 0) {
set j = (+ $j $c)
}
if (or (is-neg $i) (is-neg $j) (>= $i $c) (>= $j $c)) {
fail 'index out of range'
}
if (== $i $j) {
all $l
} else {
if (> $i $j) {
set i j = $j $i
}
take $i $l
put $l[$j]
all $l[(++ $i)..$j]
put $l[$i]
drop (++ $j) $l
}
}
fn less {|cb|
put {|a b| < ($cb $a $b) 0 }
}
fn sort {|cb @argv|
order &less-than=(less $cb) (-l $@argv)
}