crell/ordered-collection

一个快速且健壮的优先级和拓扑排序库。

2.0.0 2024-04-08 01:06 UTC

This package is auto-updated.

Last update: 2024-09-15 17:59:20 UTC


README

Latest Version on Packagist Software License Total Downloads

有序集合就是它所说的那样;它是一个基于优先级值或拓扑排序(之前/之后)对任意项进行排序的灵活工具。它包含两个实现,OrderedCollectionMultiOrderedCollection。前者稍微快一些,而后者功能更强大。

有关优先级和拓扑排序的更多信息,请参阅比较结果的这篇基准博客文章

OrderedCollection

OrderedCollection 支持通过整数优先级或单个之前/之后值对项目进行排序。内部,它将之前/之后信息转换为优先级值,然后根据优先级对整个列表进行排序。这通常比拓扑排序更快,但不能处理每个项目超过一个之前/之后条目,也不能检测之前/之后排序中的循环依赖。

首先,创建一个新的集合

use Crell\OrderedCollection\OrderedCollection;

$collection = new OrderedCollection();

现在,可以使用 addItem()addItemBefore()addItemAfter() 将任意项目添加到集合中。每个项目可以是任意值,它们不需要是同一类型。

添加项目时,您可以提供 $id。如果不提供,将自动创建一个。由该方法返回的 ID 将是所使用的 ID。ID 对于之前/之后排序是必要的。如果 ID 已经在使用中,将自动添加一个数字后缀以确保唯一性。

// Adds an item with priority 3, and a random ID will be generated.
$kirk = $collection->addItem('James T. Kirk', 3);

// Adds an item with priority 5, and an ID of "picard".
$picard = $collection->addItem('Jean-Luc Picard', 5, 'picard');

// Adds an item to some somewhere after another item, by its ID. 
// The ID for it will be auto-generated
$sisko = $collection->addItemAfter($picard, 'Benjamin Sisko');

// Adds an item to some somewhere before another item, by its ID.
// The new item's ID will be "janeway".
$janeway = $collection->addItemBefore($kirk, 'Katheryn Janeway', 'janeway');

一旦添加了项目,它们将在第一次迭代集合时自动排序。OrderedCollection 实现了 \IteratorAggregate,因此您可以使用 foreach()iterator_to_array() 来获取值。

foreach ($collection as $item) {
    print $item . PHP_EOL;
}

在这种情况下,输出将如下所示

Katheryn Janeway
Jean-Luc Picard
Benjamin Sisko
James T. Kirk

MultiOrderedCollection

这个第二个、更健壮的选项与 OrderedCollection 非常相似,并且两者都实现了相同的 OrderableCollection 接口。然而,MultiOrderedCollection 有一个额外的 add() 方法,它可以处理优先级、之前和之后排序,并支持同一项目上的多个之前/之后条目。因此,建议使用 add()MultiOrderedCollection,尽管公共接口在两者上仍将正常工作。

MultiOrderedCollection 将所有优先级转换为“之前”条目,然后对集合进行拓扑排序。这可能会稍微慢一些,但它支持单个项目上的多个之前/之后指令,并且还会检测循环依赖,这会触发一个 CycleFound 异常。

add() 方法的签名如下所示

add(
    mixed $item,
    ?string $id = null,
    ?int $priority = null,
    array $before = [],
    array $after = [],
): string

返回值是分配给值的 ID,然后可以用于之前/之后排序。值得注意的是,$before$after 参数接受一个数组,而不是单个 ID。此外,由于有许多选项,强烈建议使用命名参数。

上面的示例在 MultiOrderedCollection 上看起来是这样的

use Crell\OrderedCollection\MultiOrderedCollection;

$collection = new MultiOrderedCollection();

// Adds an item with priority 3, and a random ID will be generated.
$kirk = $collection->add('James T. Kirk', priority: 3);

// Adds an item with priority 3, and an ID of "picard".
$picard = $collection->add('Jean-Luc Picard', priority: 5, id: 'picard');

// Adds an item to some somewhere after another item, by its ID.
// The ID for it will be auto-generated
$sisko = $collection->add('Benjamin Sisko', after: ['picard']);

// Adds an item to some somewhere before another item, by its ID.
// The new item's ID will be "janeway".
$janeway = $collection->add('Katheryn Janeway', before: [$kirk], id: 'janeway');

foreach ($collection as $item) {
    print $item . PHP_EOL;
}

在这种情况下,输出将与之前相同。

Katheryn Janeway
Jean-Luc Picard
Benjamin Sisko
James T. Kirk

保证

OrderedCollectionMultiOrderedCollection 对返回的值列表提供以下保证

  • 优先级整数更高的项将排在优先级整数较低的项之前。
  • 列出为“在...之前”的项将排在那个项之前。
  • 列出为“在...之后”的项将排在那个项之后。

它们不提供以下保证,因此虽然可能发生,但不应该依赖它们。

  • 排在另一个项“之前”的项可能不会立即排在前面。它们之间可能还有其他项。
  • 排在另一个项“之后”的项可能不会立即排在后面。它们之间可能还有其他项。
  • 添加项的顺序无关紧要。在OrderedCollection中,具有相同优先级的项通常会按照它们添加的顺序返回,但这不是保证。在MultiOrderedCollection中,它们可能不会按照添加的顺序返回。简而言之,如果您关心顺序,请明确指定。

类型

在排序过程中根本不使用正在排序的项。虽然上面的例子显示了字符串,但您可以使用数组、对象、字符串、数字或您想要的任何其他内容。它们可以是同一类型,也可以是不同类型。集合对象不关心。

变更日志

有关最近更改的更多信息,请参阅变更日志

测试

$ composer test

贡献

有关详细信息,请参阅贡献指南行为准则

安全

如果您发现任何与安全相关的问题,请使用GitHub安全报告表而不是问题队列。

鸣谢

许可协议

小于GPL版本3或更高版本。请参阅许可文件以获取更多信息。