smoren/containers

Abstract data containers and structures for PHP

v0.2.8 2022-08-17 07:47 UTC

This package is auto-updated.

Last update: 2024-04-29 04:34:35 UTC


README

Packagist PHP Version Support Scrutinizer Code Quality Coverage Status Build and test License: MIT

Abstract data containers and structures for PHP

How to install as dependency to your project

composer require smoren/containers

Unit testing

composer install
./vendor/bin/codecept build
./vendor/bin/codecept run unit tests/unit

LinkedList

Classic implementation of linked list structure. Also can be used as stack and queue.

use Smoren\Containers\Structs\LinkedList;
use Smoren\Containers\Structs\LinkedListItem;

$ll = new LinkedList([6, 4, 2]);
var_dump($ll->count()); // output: 3

$ll->pushBack(1);
$ll->pushFront(7);
var_dump($ll->count()); // output: 5
print_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: 7
var_dump($ll->popBack()); // output: 1
print_r($ll->toArray()); // output: [6, 4, 2]

$ll->delete($ll->getFirst()->getNext());
print_r($ll->toArray()); // output: [6, 2]

$llNew = LinkedList::merge(new LinkedList([-2, -1]), $ll, new LinkedList([1, 2]));
var_dump($llNew->count()); // output: 6
print_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($ll as $id => $item) {
    // you can iterate collection
}

$ll->clear();
print_r($ll->toArray()); // output: []

MappedCollection

Map-like data structure.

use Smoren\Containers\Exceptions\MappedCollectionException;
use Smoren\Containers\Structs\MappedCollection;

$coll = new MappedCollection(['1' => ['id' => 1]]);
var_dump($coll->count()); // output: 1
print_r($coll->toArray()); // output: ['1' => ['id' => 1]]

$coll->add('2', ['id' => 2]);
var_dump($coll->count()); // output: 1
print_r($coll->toArray()); // output: ['1' => ['id' => 1], '2' => ['id' => 2]]

var_dump($coll->exist(1)); // output: true
var_dump($coll->exist(2)); // output: true
var_dump($coll->exist(3)); // output: false

try {
    $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($coll as $id => $item) {
    // you can iterate collection
}

$coll->clear();
print_r($coll->toArray()); // output: []

MappedLinkedList

LinkedList with mapping by id.

use Smoren\Containers\Structs\MappedLinkedList;

$mll = new MappedLinkedList([]);
var_dump($mll->count()); // output: 0

$mll->pushBack(102, 2);
$mll->pushFront(101, 1);
$mll->pushBack(100, 0);
var_dump($mll->count()); // output: 4
print_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(
    new MappedLinkedList([-999 => -99]),
    $mll,
    new MappedLinkedList([999 => 99])
);
var_dump($mllNew->count()); // output: 5
print_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($mllNew as $id => $value) {
    // you can iterate collection
}

$mllNew->clear();
print_r($mllNew->toArray()); // output: []

SortedLinkedList

use Smoren\Containers\Structs\SortedLinkedList;
use Smoren\Containers\Exceptions\LinkedListException;

/**
 * Class IntegerSortedLinkedList
 */
class IntegerSortedLinkedList extends SortedLinkedList
{
    /**
     * @inheritDoc
     */
    protected function getComparator(): callable
    {
        return function(int $lhs, int $rhs) {
            return $lhs > $rhs;
        };
    }
}

$sll = new IntegerSortedLinkedList([2, 5, 1]);
var_dump($sll->count()); // output: 3
print_r($sll->toArray()); // output: [1, 2, 5]

$sll->insert(2);
$pos = $sll->insert(3);
var_dump($sll->count()); // output: 5
print_r($sll->toArray()); // output: [1, 2, 2, 3, 5]

var_dump($sll->delete($pos)); // output: 3
var_dump($sll->count()); // output: 4
print_r($sll->toArray()); // output: [1, 2, 2, 5]

var_dump($sll->popBack()); // output: 5
var_dump($sll->popFront()); // output: 1
var_dump($sll->count()); // output: 2
print_r($sll->toArray()); // output: [2, 2]

/** 
 * @var string $id
 * @var mixed $value
 */
foreach($sll as $id => $value) {
    // you can iterate collection
}

$sll->clear();
var_dump($sll->count()); // output: 0
print_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
}

SortedMappedLinkedList

LinkedList with presort and mapping.

use Smoren\Containers\Exceptions\MappedLinkedListException;
use Smoren\Containers\Structs\LinkedListItem;
use Smoren\Containers\Structs\SortedMappedLinkedList;

$smll = new SortedMappedLinkedList([1 => -1, 10 => -10, 5 => -5]);
var_dump($smll->count()); // output: 3
print_r($smll->toArray()); // output: [1 => -1, 5 => -5, 10 => -10]

$smll->insert(3, -3);
var_dump($smll->count()); // output: 4
print_r($smll->toArray()); // output: [1 => -1, 3 => -3, 5 => -5, 10 => -10]

$smll->popBack();
$smll->popFront();
var_dump($smll->count()); // output: 2
print_r($smll->toArray()); // output: [3 => -3, 5 => -5]

/**
 * Class ArrayMappedSortedLinkedList
 */
class ArraySortedMappedLinkedList extends SortedMappedLinkedList
{
    /**
     * @inheritDoc
     */
    protected function getComparator(): callable
    {
        return function(array $lhs, array $rhs) {
            return $lhs['a'] > $rhs['a'];
        };
    }
}

$ll = new ArraySortedMappedLinkedList([
    -5 => ['a' => 5],
    -1 => ['a' => 1],
    -2 => ['a' => 2],
]);
var_dump($smll->count()); // output: 3
print_r($smll->toArray()); // output: [-1 => ['a' => 1], -2 => ['a' => 2], -5 => ['a' => 5]]

/** 
 * @var string $id
 * @var mixed $value
 */
foreach($smll as $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: 2
print_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: 0
print_r($smll->toArray()); // output: []

Graph

Graph data structure with tools for traversing.

use Smoren\Containers\Structs\Graph;

$graph = new Graph(
    [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: 3
var_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: 3
var_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: 3
var_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]