Abstract data containers and structures for PHP
composer require smoren/containers
composer install
./vendor/bin/codecept build
./vendor/bin/codecept run unit tests/unit
Classic implementation of linked list structure. Also can be used as stack and queue.
useSmoren\Containers\Structs\LinkedList;
useSmoren\Containers\Structs\LinkedListItem;
$ll = newLinkedList([6, 4, 2]);
var_dump($ll->count()); // output: 3$ll->pushBack(1);
$ll->pushFront(7);
var_dump($ll->count()); // output: 5print_r($ll->toArray()); // output: [7, 6, 4, 2, 1]$ll->sort(function($lhs, $rhs) {
return$lhs > $rhs;
});
print_r($ll->toArray()); // output: [1, 2, 4, 6, 7]$ll->swap($ll->getFirst(), $ll->getLast());
print_r($ll->toArray()); // output: [7, 2, 4, 6, 1]$ll->swap($ll->getFirst()->getNext(), $ll->getLast()->getPrev());
print_r($ll->toArray()); // output: [7, 6, 4, 2, 1]var_dump($ll->popFront()); // output: 7var_dump($ll->popBack()); // output: 1print_r($ll->toArray()); // output: [6, 4, 2]$ll->delete($ll->getFirst()->getNext());
print_r($ll->toArray()); // output: [6, 2]$llNew = LinkedList::merge(newLinkedList([-2, -1]), $ll, newLinkedList([1, 2]));
var_dump($llNew->count()); // output: 6print_r($llNew->toArray()); // output: [-2, -1, 6, 2, 1, 2]$ll->pushBefore($ll->getFirst(), -3);
$ll->pushAfter($ll->getLast(), 3);
print_r($llNew->toArray()); // output: [-3, -2, -1, 6, 2, 1, 2, 3]/** * @var LinkedListItem $id * @var mixed $item */foreach($llas$id => $item) {
// you can iterate collection
}
$ll->clear();
print_r($ll->toArray()); // output: []Map-like data structure.
useSmoren\Containers\Exceptions\MappedCollectionException;
useSmoren\Containers\Structs\MappedCollection;
$coll = newMappedCollection(['1' => ['id' => 1]]);
var_dump($coll->count()); // output: 1print_r($coll->toArray()); // output: ['1' => ['id' => 1]]$coll->add('2', ['id' => 2]);
var_dump($coll->count()); // output: 1print_r($coll->toArray()); // output: ['1' => ['id' => 1], '2' => ['id' => 2]]var_dump($coll->exist(1)); // output: truevar_dump($coll->exist(2)); // output: truevar_dump($coll->exist(3)); // output: falsetry {
$coll->add('1', ['id' => 1, 'extra' => 'test']);
} catch(MappedCollectionException$e) {
// cannot silently replace existing value
}
print_r($coll->get(1)); // output: ['id' => 1]$coll->replace('1', ['id' => 1, 'extra' => 'test']);
print_r($coll->get(1)); // output: ['id' => 1, 'extra' => 'test']try {
$coll->get('3');
} catch(MappedCollectionException$e) {
// element with id = 3 does not exist so you cannot get it
}
/** * @var string $id * @var mixed $item */foreach($collas$id => $item) {
// you can iterate collection
}
$coll->clear();
print_r($coll->toArray()); // output: []LinkedList with mapping by id.
useSmoren\Containers\Structs\MappedLinkedList;
$mll = newMappedLinkedList([]);
var_dump($mll->count()); // output: 0$mll->pushBack(102, 2);
$mll->pushFront(101, 1);
$mll->pushBack(100, 0);
var_dump($mll->count()); // output: 4print_r($mll->toArray()); // output: [101 => 1, 102 => 2, 100 => 0]]$mll->sort(function($lhs, $rhs) {
return$lhs > $rhs;
});
print_r($mll->toArray()); // output: [100 => 0, 101 => 1, 102 => 2]]$mll->swap(100, 101);
print_r($mll->toArray()); // output: [101 => 1, 100 => 0, 102 => 2]]var_dump($mll->popFront()); // output: [101, 1]var_dump($mll->popBack()); // output: [102, 2]print_r($mll->toArray()); // output: [100 => 0]$mllNew = MappedLinkedList::merge(
newMappedLinkedList([-999 => -99]),
$mll,
newMappedLinkedList([999 => 99])
);
var_dump($mllNew->count()); // output: 5print_r($mllNew->toArray()); // output: [-999 => 99, 100 => 0, 999 => 9]$mllNew->pushBefore(100, -101, -1);
$mllNew->pushAfter(100, 101, 1);
print_r($mllNew->toArray()); // output: [-999 => 99, -101 => -1, 100 => 0, 101 => 1, 999 => 9]/** * @var string $id * @var mixed $value */foreach($mllNewas$id => $value) {
// you can iterate collection
}
$mllNew->clear();
print_r($mllNew->toArray()); // output: []useSmoren\Containers\Structs\SortedLinkedList;
useSmoren\Containers\Exceptions\LinkedListException;
/** * Class IntegerSortedLinkedList */class IntegerSortedLinkedList extends SortedLinkedList
{
/** * @inheritDoc */protectedfunctiongetComparator(): callable
{
returnfunction(int$lhs, int$rhs) {
return$lhs > $rhs;
};
}
}
$sll = newIntegerSortedLinkedList([2, 5, 1]);
var_dump($sll->count()); // output: 3print_r($sll->toArray()); // output: [1, 2, 5]$sll->insert(2);
$pos = $sll->insert(3);
var_dump($sll->count()); // output: 5print_r($sll->toArray()); // output: [1, 2, 2, 3, 5]var_dump($sll->delete($pos)); // output: 3var_dump($sll->count()); // output: 4print_r($sll->toArray()); // output: [1, 2, 2, 5]var_dump($sll->popBack()); // output: 5var_dump($sll->popFront()); // output: 1var_dump($sll->count()); // output: 2print_r($sll->toArray()); // output: [2, 2]/** * @var string $id * @var mixed $value */foreach($sllas$id => $value) {
// you can iterate collection
}
$sll->clear();
var_dump($sll->count()); // output: 0print_r($sll->toArray()); // output: []try {
$sll->popBack();
} catch(LinkedListException$e) {
// cannot pop when collection is empty
}
try {
$sll->popFront();
} catch(LinkedListException$e) {
// cannot pop when collection is empty
}LinkedList with presort and mapping.
useSmoren\Containers\Exceptions\MappedLinkedListException;
useSmoren\Containers\Structs\LinkedListItem;
useSmoren\Containers\Structs\SortedMappedLinkedList;
$smll = newSortedMappedLinkedList([1 => -1, 10 => -10, 5 => -5]);
var_dump($smll->count()); // output: 3print_r($smll->toArray()); // output: [1 => -1, 5 => -5, 10 => -10]$smll->insert(3, -3);
var_dump($smll->count()); // output: 4print_r($smll->toArray()); // output: [1 => -1, 3 => -3, 5 => -5, 10 => -10]$smll->popBack();
$smll->popFront();
var_dump($smll->count()); // output: 2print_r($smll->toArray()); // output: [3 => -3, 5 => -5]/** * Class ArrayMappedSortedLinkedList */class ArraySortedMappedLinkedList extends SortedMappedLinkedList
{
/** * @inheritDoc */protectedfunctiongetComparator(): callable
{
returnfunction(array$lhs, array$rhs) {
return$lhs['a'] > $rhs['a'];
};
}
}
$ll = newArraySortedMappedLinkedList([
-5 => ['a' => 5],
-1 => ['a' => 1],
-2 => ['a' => 2],
]);
var_dump($smll->count()); // output: 3print_r($smll->toArray()); // output: [-1 => ['a' => 1], -2 => ['a' => 2], -5 => ['a' => 5]]/** * @var string $id * @var mixed $value */foreach($smllas$id => $value) {
// you can iterate collection
}
try {
$smll->insert(-2, ['a' => 2, 'extra' => 'test']);
} catch(MappedLinkedListException$e) {
// cannot simply replace existing element
}
/** @var LinkedListItem $pos */$pos = $ll->delete(-1);
print_r($pos->getData()); // output: ['a' => 1]var_dump($smll->count()); // output: 2print_r($smll->toArray()); // output: [-2 => ['a' => 2], -5 => ['a' => 5]]print_r($ll->popBack()); // output: [-5, ['a' => 5]]print_r($ll->popFront()); // output: [-2, ['a' => 2]]var_dump($smll->count()); // output: 0print_r($smll->toArray()); // output: []Graph data structure with tools for traversing.
useSmoren\Containers\Structs\Graph;
$graph = newGraph(
[1 => 11, 2 => 22, 3 => 33, 4 => 44, 5 => 55, 6 => 66],
[[1, 2, 'a'], [2, 3, 'a'], [3, 4, 'a'], [2, 5, 'b'], [5, 3, 'b'], [5, 6, 'c'], [6, 4, 'c']]
);
$paths = $graph->traverseBackward(4);
var_dump($paths); // output: 3var_dump($paths[0]->toArray(true)); // output: [4, 3, 2, 1]var_dump($paths[1]->toArray(true)); // output: [4, 3, 5, 2, 1]var_dump($paths[2]->toArray(true)); // output: [4, 6, 5, 2, 1]$paths = $graph->traverseForward(1);
var_dump(3, $paths); // output: 3var_dump($paths[0]->toArray(true)); // output: [1, 2, 3, 4]var_dump($paths[1]->toArray(true)); // output: [1, 2, 5, 3, 4]var_dump($paths[2]->toArray(true)); // output: [1, 2, 5, 6, 4]$paths = $graph->traverseForward(1, ['a', 'b']);
var_dump(2, $paths); // output: var_dump($paths[0]->toArray(true)); // output: [1, 2, 3, 4]var_dump($paths[1]->toArray(true)); // output: [1, 2, 5, 3, 4]$graph->insert(7, 77);
$graph->link(7, 1, 'a');
$paths = $graph->traverseBackward(7);
var_dump($paths); // output: 3var_dump($paths[0]->toArray(true)); // output: [4, 3, 2, 1, 7]var_dump($paths[1]->toArray(true)); // output: [4, 3, 5, 2, 1, 7]var_dump($paths[2]->toArray(true)); // output: [4, 6, 5, 2, 1, 7]var_dump($paths[2]->reverse()->toArray(true)); // output: [1, 2, 5, 6, 4, 7]