xp-forge/sequence

数据序列

v10.3.0 2024-03-24 13:25 UTC

README

Build status on GitHub XP Framework Module BSD Licence Requires PHP 7.0+ Supports PHP 8.0+ Latest Stable Version

此API允许以函数式风格处理不同类型的数据序列,例如 map/reduce。

示例

序列

可以从可迭代输入创建 util.data.Sequence 类的实例,这些输入可以是内存中的结构或数据流,例如从网络套接字读取。Sequence 类提供了中间(对单个元素进行操作,返回新的 Sequence)和终端(消耗所有元素,返回单个值)操作。

use util\data\{Sequence, Collectors, Aggregations};

$return= Sequence::of([1, 2, 3, 4])
  ->filter(fn($e) => 0 === $e % 2)
  ->toArray()
;
// $return= [2, 4]

$return= Sequence::of([1, 2, 3, 4])
  ->map(fn($e) => $e * 2)
  ->toArray()
;
// $return= [2, 4, 6, 8]

$i= 0;
$return= Sequence::of([1, 2, 3, 4])
  ->counting($i)
  ->reduce(0, fn($a, $b) => $a + $b)
;
// $i= 4, $return= 10

$names= Sequence::of($this->people)
  ->map('com.example.Person::name')
  ->collect(Collectors::joining(', '))
;
// $names= "Timm, Alex, Dude"

$experience= Sequence::of($this->employees)
  ->collect(Collectors::groupingBy(
    fn($e) => $e->department(),
    Aggregations::average(fn($e) => $e->years())
  ))
;
// $experience= util.collections.HashTable[2] {
//   Department("A") => 12.8
//   Department("B") => 3.5
// }

可选

util.data.Optional 类的实例是可能的 NULL 值的薄包装。Optional 类提供的方法有助于减少条件代码。

use util\data\Optional;

$first= Optional::of($repository->find($user));
if ($first->present()) {
  $user= $first->get();    // When Repository::find() returned non-null
}

$user= $first->orElse($this->currentUser);
$user= $first->orUse(fn() => $this->currentUser());

$name= $first
  ->filter(fn($user) => $user->isActive())
  ->whenAbsent($this->currentUser)
  ->whenAbsent(fn() => $this->guestUser())
  ->map('com.example.User::name')
  ->get()
;

创建操作

可以使用以下静态方法从各种来源创建序列:

  • of - 接受 PHP 数组(包括零索引数组和关联数组),所有可遍历的数据结构,包括 lang.types.ArrayListlang.types.ArrayMap,以及来自 util.collectionsutil.XPIterator 实例、PHP 迭代器和迭代器聚合、PHP 5.5 生成器(yield)以及序列本身。传递 NULL 将生成一个空序列。
  • iterate - 从给定的种子开始迭代,对该值应用一元运算符,并将结果传递给下一次调用,永远进行。与 limit() 结合使用!
  • generate - 永远迭代,返回给定供应商函数返回的任何内容。与 limit() 结合使用!

中间操作

以下操作返回一个新的 Sequence 实例,可以在其上调用更多中间或终端操作:

  • skip - 跳过开头的元素。使用 skip(4) 跳过前四个元素,skip(function($e) { return 'initial' === $e; }) 将跳过所有等于字符串 initial 的元素。
  • limit - 达到限制时停止迭代。使用 limit(10) 一旦返回十个元素就停止迭代,limit(function($e) { return 'stop' === $e; }) 一旦遇到等于字符串 stop 的第一个元素就停止。
  • filter - 根据给定标准过滤序列。新序列将只包含返回 true 的值。接受一个函数或一个 util.Filter 实例。
  • map - 通过对序列中的每个元素应用函数来映射每个元素,并返回一个包含该函数返回值的新序列。
  • peek - 对序列中的每个元素调用一个函数;特别适用于调试,例如 peek('var_dump', [])
  • counting - 对序列中的每个元素递增其参数给定的整数。
  • collecting - 将序列中的元素收集到 util.data.ICollector 实例中。与下面的终端操作不同,它将传递元素。
  • flatten - 将序列内部的序列扁平化,并返回一个包含所有序列值的新的列表。
  • distinct - 返回一个新的序列,它只包含唯一的元素。默认情况下使用 util.Objects::hashOf() 方法计算唯一性(但可以传递另一个函数)。
  • zip - 将值与给定的可枚举值结合,可选地使用给定的转换函数。
  • sorted - 返回一个已排序的集合。可以提供一个比较函数、一个 util.Comparator 实例或 PHP 的 sort() 函数的排序标志(例如 SORT_NUMERIC | SORT_DESC)。
  • 分块 - 返回一个分块流,其中块的大小不超过给定的值。最后一个块可能更小。
  • 窗口化 - 返回一个滑动窗口流 - 一个元素范围的列表,如果您通过给定大小的滑动窗口查看集合,您将看到这些范围。

终端操作

以下操作通过消耗整个序列返回单个值

  • toArray - 将返回一个基于零的键的PHP数组
  • toMap - 将返回一个PHP关联数组
  • first - 将返回第一个元素作为 util.data.Optional 实例。如果序列不为空,将存在值。
  • single - 与 first() 类似,但如果序列包含多个元素,将引发异常。
  • count - 将返回序列中的元素数量
  • min - 返回最小的元素。默认按数字比较,但可以提供一个比较函数或 util.Comparator 实例。
  • max - 与 min() 相同,但返回最大的元素。
  • each - 对序列中的每个元素应用给定的函数,并返回元素数量。如果没有提供函数,可以“静默地”调用以消耗。
  • reduce - 对此序列中的元素执行归约操作。
  • collect - 将此序列中的所有元素传递给 util.data.ICollector 实例。

迭代

要使用受控迭代对序列进行迭代,您可以使用 foreach 语句或通过 iterator() 访问器接收“hasNext/next”迭代器。如果序列基于可寻址的数据(经验法则:所有内存中的结构都将可寻址),则可以重复执行这些操作以获得相同的效果。否则,将引发 util.data.CannotReset 异常(例如,对于从套接字流出的数据)。

进一步阅读