b2pweb/bdf-collections

具有Java 8流API的集合实现。

v1.1.6 2024-02-26 13:38 UTC

This package is auto-updated.

Last update: 2024-09-26 14:47:55 UTC


README

实现commonscollections,带有类似Java流的转换应用。

build codecov Packagist Version Total Downloads Type Coverage

使用composer安装

composer require b2pweb/bdf-collections

使用方法

集合

所有集合实现 Bdf\Collection\CollectionInterface 接口。

集合是元素的一个简单袋子,具有一组有限的方法

  • add(mixed $element) 将元素添加到集合中。实现可能拒绝操作,并返回false。
  • addAll(iterator $elements) 等同于 foreach ($elements as $element) { $collection->add($element); }
  • clear() 删除所有元素。
  • replace(iterable $elements) 清除并替换所有元素。
  • empty() 检查集合是否没有元素。
  • contains($element, bool $strict = false) 检查集合是否包含给定元素。如果 $strict 设置为 true,则使用严格的比较运算符 ===
  • forEach(callable $callback) 使用回调遍历所有元素。
  • toArray() 将集合转换为数组。
  • 继承自 IteratorAggregateCountableStreamable 的方法

其他接口扩展了集合的基本行为

  • OrderedCollectionInterface : 确保集合的所有元素都是有序的。添加(或修改)方法
    • contains($element, bool $strict = false) 执行二分搜索。调用复杂度为O(log(n)),而不是简单集合的O(n)。
    • search($element, bool $strict = false) 获取元素位置。类似于 contains($element, bool $strict = false),但返回位置而不是 true。当 $element 存在时,表达式 $element == $collection->at($collection->search($element)) 总是 true
    • at(int $position) 获取指定位置的元素。
    • ArrayAccess 方法,期望 offsetSet()。使用位置作为偏移量。
  • SetInterface : 确保集合不包含任何重复元素。添加(或修改)方法
    • add($element) 如果集合已经包含该元素,则返回false,忽略操作。
    • addAll(iterable $elements) 如果至少有一个元素已添加,则返回false。
    • lookup($element) 查找存储在Set中的相应元素。
  • TableInterface 添加键处理以修改或访问元素
    • set($key, $value) 在给定键处设置值。
    • get($key) 在给定键处获取值。
    • hasKey($key) 检查键是否存在。
    • keys() 获取表的所有键。
    • values() 获取所有值作为数组。这与 iterator_to_array($collection) 等效。
    • forEach(callable $callback) 遍历元素,但将键作为回调的第二个参数。
    • ArrayAccess 方法

ArrayCollection

Bdf\Collection\ArrayCollection 是使用内部PHP数组实现的 TableInterface 的基本实现。它具有优异的性能,但不能处理复杂的键类型或优化搜索。

作为集合使用

<?php
$collection = new ArrayCollection(['foo']);

$collection->contains('foo'); // true
$collection->contains('bar'); // false

$collection->add('bar');
$collection->contains('bar'); // true
$collection->remove('bar');
$collection->contains('bar'); // false

$collection->add(42);
$collection->contains('42', true); // false
$collection->contains(42, true); // true

// Print "foo 42"
$collection->forEach (function ($value) {
    echo $value, ' ';
});

// Same as above
foreach ($collection as $value) {
    echo $value, ' ';
}

作为表使用

<?php
$table = new ArrayCollection(['foo' => 'bar']);

// Using methods
$table->contains('bar'); // true
$table->hasKey('foo'); // true
$table->get('foo'); // "bar"

$table->set('value', 42);
$table->contains(42); // true

// Using array access
isset($table['value']); // true
$table['value']; // 42

$table->values(); // ['bar', 42]
$table->keys(); // ['foo', 'value]

// Print "foo=bar value=42"
$table->forEach (function ($value, $key) {
    echo $key, '=', $value, ' ';
});

// Same as above
foreach ($table as $key => $value) {
    echo $key, '=', $value, ' ';
}

OrderedCollection

OrderedCollectionInterface的简单实现。在修改时不会对元素进行排序,仅在访问时进行排序。

使用方法

<?php
$collection = new OrderedCollection();

$collection->addAll([4, 9, 2, 7]);

$collection->contains(9); // true
$collection->search(4); // 1
$collection->at(2); // 7
$collection->toArray(); // [2, 4, 7, 9]

$collection->remove(7);
$collection->toArray(); // [2, 4, 9]

// Array access
$collection[0]; // 2
isset($collection[9]); // false : check the existence of the offset
isset($collection[1]); // true
$collection[] = 5; // Add the element 5
unset($collection[2]); // Remove the 3rd element (5)

// Prints 0=2 4=1 9=2
$collection->forEach(function ($element, $position) {
    echo "$position=$element ";
});

// Same as above
foreach ($collection as $position => $element) {
    echo "$position=$element ";
}

// A custom comparator can also be used
$collection = new OrderedCollection(function ($a, $b) {
    return $a->compute() - $b->compute();
});

HashSet

使用哈希函数检查元素唯一性的SetInterface实现。**注意:与Java中的常见HashSet实现不同,这里仅在比较时使用哈希码,从不使用等号运算符。**

<?php

$set = new HashSet();

$set->add('foo'); // true
$set->add('foo'); // false : already added
$set->contains('foo'); // true
$set->contains('not found'); // false

// Works also with array or objects
$set->add(['foo' => 'bar']);

$obj = new stdClass();
$set->add($obj);

$set->lookup(new stdClass())->get() === $obj; // Get the stored element, which is equals with the parameter
$set->loopup('not found')->empty(); // true : An empty optional is returned if the element is not found

$objectSet = HashSet::spl(); // Use spl_object_hash() as hash function

$obj1 = new stdClass();
$obj2 = new stdClass();

$objectSet->add($obj1);
$objectSet->contains($obj1); // true
$objectSet->contains($obj2); // false : not the same reference, hash is different

HashTable

使用哈希函数的更强大、更灵活的TableInterface实现。此实现比ArrayCollection慢约2倍。与ArrayCollection不同,支持复杂键类型(如对象)。

注意:使用复杂键时,toArray()可能会失败。

使用方法

<?php
// Use HashTable with multiple-keys indexing using array
$table = new HashTable();

$table[[123, 'aze']] = new Entity(1);
$table[[456, 'rty']] = new Entity(2);

$table[[123, 'aze']]; // Returns Entity(1)

// Use object as key
$table[new Key()] = 'value';

$table->toArray(false); // Associative array is not possible : return in form [ [key, value], ... ]

// Create a case insensitive table by registering a custom hash function
$ciTable = new HashTable('strtolower'); // Transform keys to lower case

$ciTable->set('Foo', 'bar');
$ciTable->get('FOO'); // 'bar'

Streams

使用流来转换集合元素。流实现Iterator,并可用于foreach循环。每个流方法都将返回一个新的流实例

  • map(callable $transformer)将$transformer应用于流的每个值。
  • mapKey(callable $function)将$function应用于流的每个值以生成键。
  • filter(callable $predicate)过滤掉由谓词拒绝的流元素。
  • distinct(callable $hashFunction = null)过滤流元素以获取唯一元素。可以使用自定义哈希函数。
  • sort(callable $comparator = null, bool $preserveKeys = false)对流元素进行排序。
  • concat(StreamInterface $stream, bool $preserveKeys = true)在当前流之后连接一个新的流。
  • flatMap(callable $transformer, bool $preserveKeys = false)创建一个流,该流是$transformer提取的每个元素内容的连接。
  • skip(int $count)跳过流中的前$count个元素。
  • limit(int $count, int $offset = 0)限制流中的元素数量。
  • forEach(callable $consumer)遍历所有流元素。
  • toArray(bool $preserveKeys = true)将流聚合为数组。
  • first()获取流的第一个元素。
  • reduce(callable $accumulator, $initial = null)将流的所有元素归约为单个值。
  • collect(CollectorInterface $collector)将所有元素收集为单个值。
  • matchAll(callable $predicate)检查流中的所有元素是否与谓词匹配。
  • matchOne(callable $predicate)检查流中至少有一个元素与谓词匹配。

使用方法

$stream = Streams::wrap([7, 4, 9]);

// [ 10 => 8, 16 => 14, 20 => 18]
$stream
    ->sort()
    ->map(function ($element) { return $element * 2; })
    ->mapKey(function ($element) { return $element + 2; })
    ->toArray()
;

MutableArrayStream

MutableArrayStreamStreamInterface的一个实现,用于简单的PHP数组。与其他流不同,所有转换都应用于方法调用,并返回$this而不是新的流实例。减少流的开销,以获得更好的性能,但某些方法的行为不同。

使用方法

$collection = new ArrayCollection([...]);

$stream = $collection->mutableStream(); // Get a mutable stream from an ArrayCollection
$stream = new MutableArrayStream([...]); // Or creates using constructor

// And use like other streams
$stream
    ->map(...)
    ->filter(...)
    ->collect(...)
;

Optional

Bdf\Collection\Util\Optional用于替换null值和null对象。它允许创建一个简单的null对象。方法

  • filter(callable $predicate)过滤可选值。
  • map(callable $transformer)如果存在,则转换元素。
  • apply(callable $consumer)如果存在,则对元素应用消费者。
  • or($value)如果存在,则获取当前的Optional值,如果不存在,则获取参数值。
  • orThrows($exception = RuntimeException::class)如果存在,则获取当前值,如果不存在,则抛出异常。
  • orSupply(callable $supplier)如果存在,则获取当前值,如果不存在,则返回供应商的结果。
  • present()检查Optional值是否存在。
  • get()获取当前存储的值。
  • 魔法方法,将委托给内部对象,并将返回值包装在可选对象中

使用方法

<?php

// Creates the optional
Optional::empty(); // "Null" optional
Optional::of($myValue); // Wrap $myValue into an Optional. The value must not be null
Optional::nullable($myValue); // Wrap $myValue into an Optional. The value may be null

Optional::empty()->present(); // false
Optional::of(42)->present(); // true

// Creates a simple null object
$myNullObject = Optional::nullable($person);

$myNullObject->firstName()->or('undefined'); // Call $person->firstName() if present, and get the return value, or return "undefined"
isset($myNullObject->myProp); // Check if property myProp exists into $person 

$myNullObject->stream(); // Creates a singleton or empty stream with the wrapped element.