317 lines
5.7 KiB
PHP
317 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace alveolata\list_;
|
|
|
|
// require_once(DIR_ALVEOLATA . '/definitions.php');
|
|
|
|
|
|
/**
|
|
* returns a list of integers from 0 to length-1
|
|
*
|
|
* @param int $length {integer}
|
|
* @return array {list<integer>}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sequence(
|
|
int $length
|
|
) : array
|
|
{
|
|
return (
|
|
($length <= 0)
|
|
? []
|
|
: array_merge(sequence($length-1), [$length-1])
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list1 {list<§x>}
|
|
* @param array $list2 {list<§x>}
|
|
* @return array {list<§x>}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function concat(
|
|
array $list1,
|
|
array $list2
|
|
) : array
|
|
{
|
|
return array_merge($list1, $list2);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $predicate {function<§x,boolean>}
|
|
* @return array {list<§x>}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function filter(
|
|
array $list,
|
|
\Closure $predicate
|
|
) : array
|
|
{
|
|
$list_ = [];
|
|
foreach ($list as $value) {
|
|
if ($predicate($value)) {
|
|
array_push($list_, $value);
|
|
}
|
|
}
|
|
return $list_;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $transformator {function<§x,§y>}
|
|
* @return array {list<§y>}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function map(
|
|
array $list,
|
|
\Closure $transformator
|
|
) : array
|
|
{
|
|
$list_ = [];
|
|
foreach ($list as $value) {
|
|
$value_ = $transformator($value);
|
|
array_push($list_, $value_);
|
|
}
|
|
return $list_;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param mixed $start {§y}
|
|
* @param \Closure $aggregator {function<§y,§x,§y>}
|
|
* @return mixed {§y}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function reduce_left(
|
|
array $list,
|
|
$start,
|
|
\Closure $aggregator
|
|
)
|
|
{
|
|
$result = $start;
|
|
foreach ($list as $current) {
|
|
$result = $aggregator($result, $current);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param mixed $start {§y}
|
|
* @param \Closure $aggregator {function<§x,§y,§y>}
|
|
* @return mixed {§y}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function reduce_right(
|
|
array $list,
|
|
$start,
|
|
\Closure $aggregator
|
|
)
|
|
{
|
|
$result = $start;
|
|
foreach (array_reverse($list) as $current) {
|
|
$result = $aggregator($current, $result);
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param mixed $start {§y}
|
|
* @param \Closure $aggregator {function<§y,§x,§y>}
|
|
* @return mixed {§y}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function reduce(
|
|
array $list,
|
|
$start,
|
|
\Closure $aggregator
|
|
)
|
|
{
|
|
return reduce_left($list, $start, $aggregator);
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $predicate {function<§x,bool>}
|
|
* @return bool {boolean}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function some(
|
|
array $list,
|
|
\Closure $predicate
|
|
) : bool
|
|
{
|
|
foreach ($list as $current) {
|
|
if ($predicate($current)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $predicate {function<§x,bool>}
|
|
* @return bool {boolean}
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function every(
|
|
array $list,
|
|
\Closure $predicate
|
|
) : bool
|
|
{
|
|
foreach ($list as $current) {
|
|
if (! $predicate($current)) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list1 {list<§x>}
|
|
* @param array $list2 {list<§y>}
|
|
* @param bool $cut {boolean} whether to take the least length in case the lists have different lengths
|
|
* @return array {list<record<first:§x,second:§y>>}
|
|
* @throw \Exception if lists have different lengths and $cut = false
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function zip(
|
|
array $list1,
|
|
array $list2,
|
|
bool $cut = true
|
|
) : array
|
|
{
|
|
$l1 = count($list1);
|
|
$l2 = count($list2);
|
|
if (! ($l1 === $l2)) {
|
|
if (! $cut) {
|
|
throw (new \Exception('lists have different lengths'));
|
|
}
|
|
else {
|
|
$length = $l1;
|
|
}
|
|
}
|
|
else {
|
|
$length = min($l1, $l2);
|
|
}
|
|
$list3 = [];
|
|
for ($index = 0; $index < $length; $index += 1) {
|
|
$pair = [
|
|
'first' => $list1[$index],
|
|
'second' => $list2[$index],
|
|
];
|
|
array_push($list3, $pair);
|
|
}
|
|
return $list3;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $order {function<§x,§x,boolean>}
|
|
* @return array {list<§x>}
|
|
* @throws \Exception if the sorting fails
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function sort(
|
|
array $list,
|
|
\Closure $order = null
|
|
) : array
|
|
{
|
|
if (is_null($order)) {
|
|
$order = (function ($x, $y) {return ($x <= $y);});
|
|
}
|
|
$copy = array_map(function ($x) {return $x;}, $list);
|
|
$successful = usort(
|
|
$copy,
|
|
function ($x, $y) use ($order) : int {
|
|
return ($order($x, $y) ? (-1) : (+1));
|
|
}
|
|
);
|
|
if (! $successful) {
|
|
throw (new \Exception('alveolata_list_sort_failed'));
|
|
}
|
|
else {
|
|
return $copy;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $list {list<§x>}
|
|
* @param \Closure $collation {function<§x,§x,boolean>}
|
|
* @return array {list<list<§x>>}
|
|
*/
|
|
function group(
|
|
array $list,
|
|
\Closure $collation
|
|
) : array
|
|
{
|
|
$groups = [];
|
|
foreach ($list as $element) {
|
|
$found = false;
|
|
foreach ($groups as &$group) {
|
|
if ($collation($group[0], $element)) {
|
|
array_push($group, $element);
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
unset($group);
|
|
if (! $found) {
|
|
$group = [$element];
|
|
array_push($groups, $group);
|
|
}
|
|
}
|
|
return $groups;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param array $x {list<type_x>}
|
|
* @param array $y {list<type_y>}
|
|
* @param ?array $options {
|
|
* (
|
|
* null
|
|
* |
|
|
* record<
|
|
* ?combinator:function<tuple<type_x,type_y>,any>,
|
|
* >
|
|
* )
|
|
* }
|
|
* @return array {list<tuple<type_x,type_y>>}
|
|
*/
|
|
function product(
|
|
array $x,
|
|
array $y,
|
|
?array $options = null
|
|
) : array
|
|
{
|
|
$options = \array_merge(
|
|
[
|
|
'combinator' => (fn($u, $v) => [$u, $v])
|
|
],
|
|
($options ?? [])
|
|
);
|
|
$z = [];
|
|
foreach ($x as $u) {
|
|
foreach ($y as $v) {
|
|
\array_push($z, $options['combinator']($u, $v));
|
|
}
|
|
}
|
|
return $z;
|
|
}
|
|
|
|
?>
|