PHP code example of hadasbro / php-streams

1. Go to this page and download the library: Download hadasbro/php-streams library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

hadasbro / php-streams example snippets


composer 

 
# Init via constructor
$stream = new CollectionsStream([1, 2, 3, 4, 5, 6, 7]);

# Init via CollectionsStream::fromIterable
$stream = CollectionsStream::fromIterable([1, 2, 3, 4, 5]);

# Init via CollectionsStream::fromStartValueAndTransformer
$stream = CollectionsStream::fromStartValueAndTransformer(1, 15, function ($value) {return $value + 1;});

# Init via CollectionsStream::fromStartValueAndTransformer - PHP 7.4 arrow functions
$stream = CollectionsStream::fromStartValueAndTransformer(1, 15, fn ($value) => $value + 1);

# Init via CollectionsStream::fromProducer
$stream = CollectionsStream::fromProducer(function () { 
    $data = []; for($i = 1; $i < 20; $i++){ $data[] = $i; }; return $data; 
});

# CollectionsStream::fromParams
$stream = CollectionsStream::fromParams(1, 2, 3, 4, 5);


class SampleObj
{
    private int $id;
    private int $type = 1;

    public function __construct($lineId, $type = 1){
        $this->id = $lineId;
        $this->type = $type;
    }

    public function getId(): int
    {
        return $this->id;
    }

    public function setId(int $id): self
    {
        $this->id = $id;
        return $this;
    }

    public function getType(): int
    {
        return $this->type;
    }

    public function setType(int $type): self
    {
        $this->type = $type;
        return $this;
    }

}

class StreamTest extends TestCase
{
    public function testStream()
    {

        $manyObjects = [
            new SampleObj(0, 13),
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1),
            new SampleObj(21, 777),
            new SampleObj(0, 134),
        ];

        /**
         * @var $stream CollectionsStream
         */
        $stream = CollectionsStream::fromIterable($manyObjects);
        
        $reducedStream = 
            
            $stream

            ->map(fn(SampleObj $obj) => ($obj->getType() == 13 && $obj->setType(444)) ? $obj : $obj)
            
            ->filter(fn(SampleObj $obj) => $obj->getId() != 1)
            
            ->reject(fn(SampleObj $obj) => $obj->getType() == 777)
            
            ->distinct(fn(SampleObj $obj1, SampleObj $obj2) => $obj1->getType() == $obj2->getType())
            
            ->orElse(fn(SampleObj $obj1) => $obj1->getId() == 0, new SampleObj(1, 1))
            
            ->sort(fn(SampleObj $obj1, SampleObj $obj2) => $obj1->getId() >= $obj2->getId())
            
            ->groupBy(fn(SampleObj $obj) => $obj->getType())

            ->reduce(
                fn ($acumulated, array $obj) => ($acumulated = array_merge([], is_array($acumulated) ? $acumulated : [], array_values($obj))) ? $acumulated : $acumulated
            );

        var_dump($reducedStream);
        /*
            [
                SampleObj(33, 2),
                SampleObj(7, 11),
                SampleObj(2, 1),
                SampleObj(1, 1),
                SampleObj(1, 1)
            ]
        */

    }

}

class _StreamExamples
{
    public static function stream()
    {
        $manyObjects = [
            new SampleObj(0, 13),
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1),
            new SampleObj(21, 777),
            new SampleObj(0, 134),
        ];

        /**
         * @var $stream CollectionsStream
         */
        $stream = CollectionsStream::fromIterable($manyObjects);
        
        $stream

            # change type from 13 => 444
            ->map(function (SampleObj $obj) {
                if ($obj->getType() == 13) $obj->setType(444);
                return $obj;
            })

            # get only objects with ID != 1
            ->filter(function (SampleObj $obj) {
                return $obj->getId() != 1;
            })

            # remove objects with type = 777
            ->reject(function (SampleObj $obj) {
                return $obj->getType() == 777;
            })

            # get only unique ones (unique = with different type)
            ->distinct(function (SampleObj $obj1, SampleObj $obj2) {
                return $obj1->getType() == $obj2->getType();
            })

            # consider every object with ID = 0 as "empty"/null object we dont want
            # and replace such object to default one SampleObj(1, 1);
            ->orElse(function (SampleObj $obj1) {
                return $obj1->getId() == 0;
            }, new SampleObj(1, 1))

            # sort objects from the highest ID to the lowest
            ->sort(function (SampleObj $obj1, SampleObj $obj2) {
                return $obj1->getId() >= $obj2->getId();
            })

            # group our collection by object's type
            # after groupping in the stream we will have array like below one
            # [2 => [ SampleObj(33, 2) ], 11 => [ SampleObj(7, 11)]]
            ->groupBy(function (SampleObj $obj) {
                return $obj->getType();
            });


        # now we can e.g. transform that array of elements back
        # to simple list of objects by using reducer
        # [ SampleObj(33, 2), SampleObj(7, 11) ...]

        $reducedStream = $stream
            ->reduce(function ($acumulated, array $obj) {
                $acumulated ??= [];
                $acumulated = array_merge($acumulated, array_values($obj));
                return $acumulated;
            });

        var_dump($reducedStream);
        /*
            [
                SampleObj(33, 2),
                SampleObj(7, 11),
                SampleObj(2, 1),
                SampleObj(1, 1),
                SampleObj(1, 1)
            ]
        */

        # we can also reduce it to e.g. concatenation of those objects' IDs
        $reducedToIds = $stream

            ->reduce(function ($acumulated, $obj) {
                
                $acumulated ??= '';

                foreach ($obj as $item) {
                    $acumulated .= ',' . strval($item->getId());
                }

                return ltrim($acumulated, ',');
            });

        var_dump($reducedToIds); // 33,7,2,1,1
        
    }

}

class _CollectorsExamples
{

    public static function generalTest() {

        try {

            $manyObjects = [
                new SampleObj(1, 13),
                new SampleObj(14, 13),
                new SampleObj(7, 11),
                new SampleObj(14, 13),
                new SampleObj(33, 2),
                new SampleObj(33, 11),
                new SampleObj(2, 1)
            ];

            # join all IDs into 1 string separated by commas
            $collector = Collector::of(Collector::JOINING, function (CollectionsSampleObject $obj) { return $obj->getId(); });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected); // '1,14,7,14,33,33,2'
    
            # Join with custom separator - @
            $collector = Collector::of(Collector::JOINING, function (CollectionsSampleObject $obj) { return ['value' => $obj->getId(), 'separator' => '@']; });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected); // 1@14@7@14@33@33@2

            # sum all elements
            $collector = Collector::of(Collector::SUMMING, function (SampleObj $obj) { return $obj->getId(); });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // 104

            # multiply all elements
            $collector = Collector::of(Collector::MULTIPLYING, function (SampleObj $obj) { return $obj->getId(); });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // 2 988 216

            # put all elements to array
            $collector = Collector::of(Collector::TO_FLAT_ARRAY, function (SampleObj $obj) { return $obj->getId(); });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // [ 1, 14, 7, 14, 33, 33, 2 ]

            # return string with all alements wrapped by single quote
            $collector = Collector::of(Collector::TO_CONCAT_OF_STRINGS, function (SampleObj $obj) { return $obj->getId(); });
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // '1','14','7','14','33','33','2'

            # generate and return associative array of elements
            $collector = Collector::of(Collector::TO_ASSOC_ARRAY, function (SampleObj $obj) { 
                # here, in extractor, we need to define how do we want to 
                # generate key and value for each element
                return ['key' => $obj->getType(), 'value' => $obj]; 
            });

            $collected = Collections::collect($manyObjects, $collector);

            va($collected);
            /*
                [
                    13 => new SampleObj(14, 13),
                    11 => new SampleObj(33, 11),
                    2 => new SampleObj(2, 2)
                    1 => new SampleObj(2, 1)
                ]
            */


        } catch (\Throwable $t) {
            vae($t);
        }


    }

}

class Collector extends CollectorOperations {
    
    const JOINING = 1; # [a, b, c] -> a,b,c
    const SUMMING = 2; # [a, b, c] -> a + b + c
    const MULTIPLYING = 3; # [a, b, c] -> a * b * c
    const TO_FLAT_ARRAY = 4; # [obj1, obj2, obj3] -> [ obj1->getId(), obj2->getId(), obj3->getId()]
    const TO_CONCAT_OF_STRINGS = 5; # [obj1, obj2] -> ['{obj1->getId()}', '{obj2->getId()}']
    
    /*
     * Note: if you use this collector, then your extractor must
     * specify how do you want to generate keys and values from your data
     * Your extractor must return [key => _how_to_obtain_key_, value => _how_to_obtain_value_ ]
     *
     * for example:
     *
     *      $collector = Collector::of(
     *          Collector::TO_ASSOC_ARRAY,
     *          function ($obj) { return ['key' => $obj->getId(), 'value' => $obj]; }
     *      );
     *
     */
    const TO_ASSOC_ARRAY = 6; # [obj1, obj2] -> [obj1->getId() => obj1, obj2->getId() => obj2]
}

class _AllMatchExamples
{
    public static function allMatch()
    {
        $manyObjects = [1, 2, 3, 4, 5];
        $objects = [21, 17, 1, 2, 3, 4, 5, 666];

        $allMatch = Collections::allMatch($manyObjects, function (int $obj1) use ($objects) {
            # predicate method should return TRUE if we consider element as
            # matching to our criteria or FALSE if element doesnt match
            return in_array($obj1, $objects);
        });

        var_dump($allMatch); // true

    }
}

class _CollectionsExamples
{
    public static function distinct()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(14),
            new SampleObj(33),
            new SampleObj(33),
        ];

        $unique = Collections::distinct($manyObjects, function (SampleObj $obj1, SampleObj $obj2) {
            # comparator should return TRUE if $obj1 is equal $obj2
            # or FALSE if we consider $obj1 and $obj2 as unequal
            # this is in terms of any criteria we want to apply
            return $obj1->getId() == $obj2->getId();
        });

        var_dump($unique); # [ SampleObj(14),  SampleObj(7),  SampleObj(33), ]

    }

}


class _FilterExamples
{
    public static function filter()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $filteredResult = Collections::filter($manyObjects, function (SampleObj $obj) {
            return $obj->getId() < 11;
        });

        var_dump($filteredResult); #   [ SampleObj(7), SampleObj(1) ]

    }
}


class _RejectExamples
{
    public static function reject()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $filteredResult = Collections::reject($manyObjects, function (SampleObj $obj) {
            return $obj->getId() < 11;
        });

        var_dump($filteredResult); # [ SampleObj(14), SampleObj(33) ]

    }

}



class _MapExamples
{
    public static function map()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7)
        ];

        $mappedResult = Collections::map($manyObjects, function (SampleObj $obj) {
            $obj->setId($obj->getId() + 100);
            return $obj;
        });

        var_dump($mappedResult); #   [ SampleObj(114), SampleObj(107) ]

    }

}


class _MinMaxExamples
{
    public static function minMax()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $minElement = Collections::min($manyObjects, function (SampleObj $obj1, SampleObj $obj2) {
            # comparator should return TRUE if $obj1 < $obj2
            # in terms of any criteria we want to apply
            return $obj1->getId() < $obj2->getId();
        });

        var_dump($minElement); # new SampleObj(1),
        var_dump($minElement->getId()); # 1

    }

}

class _SortExamples
{
    public static function sort()
    {
        $manyObjects = [
            new SampleObj(1),
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(14),
            new SampleObj(33),
            new SampleObj(33),
            new SampleObj(2)
        ];

        # order ASC (from the smallest object's IDs)
        $sortedCollection = Collections::sort($manyObjects, function (SampleObj $obj1, SampleObj $obj2) {
            # sorter should return TRUE if $obj1 is < $obj2, so if we expect order [$obj1, $obj2]
            # or oposite - FALSE - if we expect order [$obj1, $obj2]
            # this is in terms of any criteria we want to apply
            return $obj1->getId() < $obj2->getId();
        });

        var_dump($sortedCollection);
        /* 
            [
                new SampleObj(1),
                new SampleObj(2),
                new SampleObj(7),
                new SampleObj(14),
            ] 
        */

    }
}

class _OrElseExamples
{
    public static function orElse()
    {
        $manyObjects = [
            new SampleObj(0),
            new SampleObj(14),
            new SampleObj(-1),
            new SampleObj(14),
            new SampleObj(-22)
        ];

        # order ASCE (from the smallest object's IDs)
        $collection = Collections::orElse($manyObjects, function (SampleObj $obj1) {
            # return TRUE if we consider that particular object as "NULL" in any meaning
            # (if we want to replace that kind of object to any other - default one)
            # here - every object with ID <= 0 we consider as "NULL one" and we want
            # to use default object (SampleObj(100)) instead
            return $obj1->getId() <= 0;
        }, new SampleObj(100));

        var_dump($collection);
        /* 
            [
                new SampleObj(100),
                new SampleObj(14),
                new SampleObj(100),
                new SampleObj(14),
                new SampleObj(100)
            ]
        */


    }
}

class _ReduceExamples
{
    public static function reduce()
    {
        $manyObjects = [
            new SampleObj(0),
            new SampleObj(14),
            new SampleObj(-1),
            new SampleObj(14),
            new SampleObj(-22)
        ];

        # reduce array of objects to array if [ID#objects_id, ..., ID#objects_id]
        $reduced = Collections::reduce($manyObjects, function ($ids, SampleObj $obj) {
            
            # reducer is methos as the following
            # function ($reducedElement, $nextElement) { return $reducedElement; }
            # in reducet we should perform any kind of changes on $reducedElement in terms of any next $nextElement
            # e.g. sum/add next integer to already existing sum, add another element to array etc.

            $ids ??= [];
            $ids[] = 'ID#' . $obj->getId();
            return $ids;
        });

        var_dump($reduced);
        /* ["ID#0","ID#14","ID#-1", "ID#14", "ID#-22"] */

    }
}


class _GroupByExamples
{
    public static function group()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        # normal count
        $groupped = Collections::groupBy(
            $manyObjects,
            function (SampleObj $obj) {
                return $obj->getType();
            }
        );

        var_dump($groupped);
        /*
            [
                13 => [SampleObj(1, 13), SampleObj(14, 13), SampleObj(14, 13)],
                11 => [SampleObj(7, 11), SampleObj(33, 11)],
                2 => [SampleObj(33, 2)],
                1 => [SampleObj(2, 1)]
            ]
        */

    }

}


class _CountExamples
{
    public static function countBy()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        # normal count
        $count = Collections::count($manyObjects);
        var_dump($count); # 7


        # count with groupping by object's type
        $counted = Collections::countBy(
            $manyObjects,
            function (SampleObj $obj) {
                return $obj->getType();
            }
        );

        var_dump($counted);
        /*
        [
            13 => 3
            11 => 2
            2 => 1
            1 => 1
        ]
        */

    }

}

class _ContainsSearch
{
    public static function contains()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        $contains = Collections::contains($manyObjects, function (SampleObj $obj1) {
            return $obj1->getId() == 14;
        });

        $contains2 = Collections::contains($manyObjects, function (SampleObj $obj1) {
            return $obj1->getId() == 144;
        });

        $search = Collections::search($manyObjects, function (SampleObj $obj1) {
            return $obj1->getId() == 144;
        });

        $search2 = Collections::search($manyObjects, function (SampleObj $obj1) {
            return $obj1->getType() == 13;
        });

        var_dump($contains); // true
        var_dump($contains2); // false
        var_dump($search); // []
        var_dump($search2); // [ SampleObj(1, 13), SampleObj(14, 13), SampleObj(14, 13) ]

    }

}

class _ForeachExamples
{
    public static function foreach()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        Collections::forEach($manyObjects, function (SampleObj $obj1) {
            echo ' We just want to pring object ID whic is # ' . $obj1->getId() . PHP_EOL;
        });

        /*
            We just want to pring object ID whic is # 1
            We just want to pring object ID whic is # 14
            We just want to pring object ID whic is # 7
            We just want to pring object ID whic is # 14
            We just want to pring object ID whic is # 33
            We just want to pring object ID whic is # 33
            We just want to pring object ID whic is # 2
      */

    }

}




class _ToArrayAssocExamples
{
    public static function toAssocArray()
    {       
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        try{
            # stict - dont tolerate dupplicated keys
            $assocArray = Collections::toAssocArray($manyObjects, function (SampleObj $obj1) {
                return $obj1->getType();
            });
            /*
                <Exception> CollectionsInvalidInputException
                'Not unique key in Collections::toAssocArray.
                Strict mode nored because we already have
            # assoc array, so we dont modify current keys and values
            return 123;
        }, false);
        /*
            ['a' => 1, 'b' => 2]
        */

    }

}


class _OtherMethodsExamples
{
    public static function test()
    {
        
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $empty = Collections::isEmpty($manyObjects);
        $notEmpty = Collections::isNotEmpty($manyObjects);

        var_dump([$empty, $notEmpty]); #   [ true, false ]

    }

}

class _AllMatchExamples
{

    public static function allMatch()
    {

        $manyObjects = [1, 2, 3, 4, 5];
        $objects = [21, 17, 1, 2, 3, 4, 5, 666];

        /**
         * @var $allMatch bool
         */
        $allMatch = Collections::allMatch($manyObjects, fn(int $obj1) => in_array($obj1, $objects));

        var_dump($allMatch); // true

    }
    
    public static function anyMatch(){

        $manyObjects = [1, 2, 3, 4, 5];
        $objects = [21, 17];

        /**
         * @var $anyMatch bool
         */
        $anyMatch = Collections::anyMatch($manyObjects, fn(int $obj1) => in_array($obj1, $objects));

        var_dump($anyMatch); // false
    }

}


class _FilterExamples
{

    public static function filter()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $filteredResult = Collections::filter($manyObjects, fn(SampleObj $obj) => $obj->getId() < 11);

        var_dump($filteredResult); #   [ SampleObj(7), SampleObj(1) ]

    }
}


class _RejectExamples
{

    public static function reject()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        $filteredResult = Collections::reject($manyObjects, fn (SampleObj $obj) => $obj->getId() < 11);

        var_dump($filteredResult); #   [ SampleObj(14), SampleObj(33) ]

    }

}



class _MapExamples
{

    public static function map()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7)
        ];

        $mappedResult = Collections::map($manyObjects, fn(SampleObj $obj) => $obj->setId($obj->getId() + 100) && $obj ? $obj : $obj);

        var_dump($mappedResult); #   [ SampleObj(114), SampleObj(107) ]

    }

}


class _MinMaxExamples
{

    public static function minMax()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(1),
            new SampleObj(33)
        ];

        /**
         * @var $minElement SampleObj
         */
        $minElement = Collections::min($manyObjects, fn(SampleObj $obj1, SampleObj $obj2) => $obj1->getId() < $obj2->getId());

        var_dump($minElement); # new SampleObj(1),

    }

}

class _DistinctExamples
{

    public static function distinct()
    {
        $manyObjects = [
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(14),
            new SampleObj(33),
            new SampleObj(33),
        ];

        /**
         * @var $unique SampleObj[]
         */
        $unique = Collections::distinct($manyObjects, fn(SampleObj $obj1, SampleObj $obj2) => $obj1->getId() == $obj2->getId());

        var_dump($unique); # [ SampleObj(14),  SampleObj(7),  SampleObj(33), ]

    }

}

class _SortExamples
{

    public static function sort()
    {
        $manyObjects = [
            new SampleObj(1),
            new SampleObj(14),
            new SampleObj(7),
            new SampleObj(14),
            new SampleObj(33),
            new SampleObj(33),
            new SampleObj(2)
        ];

        # order ASCE (from the smallest object's IDs)
        $sortedCollection = Collections::sort($manyObjects, fn (SampleObj $obj1, SampleObj $obj2) => $obj1->getId() < $obj2->getId());

        var_dump($sortedCollection);
        /*
            [
                new SampleObj(1),
                new SampleObj(2),
                new SampleObj(7),
                new SampleObj(14)
            ]
        */

    }
}

class _OrElseExamples
{

    public static function orElse()
    {
        $manyObjects = [
            new SampleObj(0),
            new SampleObj(14),
            new SampleObj(-1),
            new SampleObj(14),
            new SampleObj(-22)
        ];

        # order ASCE (from the smallest object's IDs)
        $collection = Collections::orElse($manyObjects, fn(SampleObj $obj1) => $obj1->getId() <= 0, new SampleObj(100));

        var_dump($collection);
        /* 
            [
                new SampleObj(100),
                new SampleObj(14),
                new SampleObj(100),
                new SampleObj(14),
                new SampleObj(100)
            ] 
        */
    }
}

class _ReduceExamples
{

    public static function reduce()
    {
        $manyObjects = ['aaa', 'bb', 'abc', 'bb'];

        $reduced = Collections::reduce($manyObjects, fn ($concatOfStrings, string $str)  => ($concatOfStrings .= $str) ? $concatOfStrings : $concatOfStrings);
        
        var_dump($reduced); //aaabbabcbb

    }
}


class _GroupByExamples
{

    public static function group()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        # normal count
        $groupped = Collections::groupBy(
            $manyObjects,
            fn (SampleObj $obj) => $obj->getType()
        );

        var_dump($groupped);
        /*
            [
                13 => [SampleObj(1, 13), SampleObj(14, 13), SampleObj(14, 13)],
                11 => [SampleObj(7, 11), SampleObj(33, 11)],
                2 => [SampleObj(33, 2)],
                1 => [SampleObj(2, 1)]
            ]
        */

    }

}

class _ContainsSearch
{

    public static function contains()
    {
        $manyObjects = [
            new SampleObj(1, 13),
            new SampleObj(14, 13),
            new SampleObj(7, 11),
            new SampleObj(14, 13),
            new SampleObj(33, 2),
            new SampleObj(33, 11),
            new SampleObj(2, 1)
        ];

        $contains = Collections::contains($manyObjects, fn(SampleObj $obj1) => $obj1->getId() == 14);

        var_dump($contains); // true

    }

}

class _CollectorsExamples
{

    public static function generalTest() {

        try {

            $manyObjects = [
                new SampleObj(1, 13),
                new SampleObj(14, 13),
                new SampleObj(7, 11),
                new SampleObj(14, 13),
                new SampleObj(33, 2),
                new SampleObj(33, 11),
                new SampleObj(2, 1)
            ];
            
            # join all IDs into 1 string separated by commas
            $collector = Collector::of(Collector::JOINING, fn (CollectionsSampleObject $obj) => $obj->getId());
            $collected = Collections::collect($manyObjects, $collector);
            va($collected); // '1,14,7,14,33,33,2'
            
            # Join with custom separator - @
            $collector = Collector::of(Collector::JOINING, fn (CollectionsSampleObject $obj) => ['value' => $obj->getId(), 'separator' => '@']);
            $collected = Collections::collect($manyObjects, $collector);
            va($collected); // 1@14@7@14@33@33@2
            
            # sum all elements
            $collector = Collector::of(Collector::SUMMING, fn (CollectionsSampleObject $obj) => $obj->getId());
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // 104
            
            # multiply all elements
            $collector = Collector::of(Collector::MULTIPLYING, fn (CollectionsSampleObject $obj) =>  $obj->getId());
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // 2 988 216
            
            # put all elements to array
            $collector = Collector::of(Collector::TO_FLAT_ARRAY, fn (CollectionsSampleObject $obj) => $obj->getId());
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // [ 1, 14, 7, 14, 33, 33, 2 ]
            
            # return string with all alements wrapped by single quote
            $collector = Collector::of(Collector::TO_CONCAT_OF_STRINGS, fn (CollectionsSampleObject $obj) => $obj->getId());
            $collected = Collections::collect($manyObjects, $collector);
            va($collected);  // '1','14','7','14','33','33','2'
            
            # generate and return associative array of elements
            $collector = Collector::of(Collector::TO_ASSOC_ARRAY, fn (CollectionsSampleObject $obj) => ['key' => $obj->getType(), 'value' => $obj]);
            $collected = Collections::collect($manyObjects, $collector);

            va($collected);
            /*
                [
                    13 => new SampleObj(14, 13),
                    11 => new SampleObj(33, 11),
                    2 => new SampleObj(2, 2)
                    1 => new SampleObj(2, 1)
                ]
            */

        } catch (\Throwable $t) {
            vae($t);
        }


    }

}

interface CollectionsContextApi
{


    # map elements in the collection to any other elements or just transforrm
    public function map(callable $mapper): self ;
    
    # filter elements in the collection
    public function filter(callable $predicate): self;
    
    # alias to filter
    public function transform(callable $predicate): self;
    
    # remove only elements matching to predicate
    public function reject(callable $predicate): self;
    
    # get the smallest/lowest/youngest element
    public function min(callable $firstIsLowerComparator);
    
    # get the biggest/highest/oldest element
    public function max(callable $firstIsLowerComparator);
    
    # check if collection is empty
    public function isEmpty(): bool;
    
    # check if collection is not empty
    public function isNotEmpty(): bool;
    
    # sort colelction
    public function sort(callable $biSorter): self;
    
    # count elements in the collection
    public function count() : int;
    
    # count elements and group by provided keys
    public function countBy(callable $keyProducer): array;
    
    # reduce collection into 1 element
    public function reduce(callable $reducer);
    
    # get distinct sub-collection
    public function distinct(callable $biPredicate): self;
    
    # check if all elements match to criteria
    public function allMatch(callable $predicate): bool;
    
    # check if any elements match to criteria
    public function anyMatch(callable $predicate): bool;
    
    # check if every element doesnt match to criteria
    public function noneMatch(callable $predicate): bool;
    
    # get sub-collection groupped by public function shuffle(): self;
    
    # skip x - elements in a collection
    public function skip(int $skipElements): self;
    
    # take only x - elements from collection
    public function limit(int $limit): self ;
    
    # reverse collection
    public function reverse(): self;

}

interface CollectionsStaticApi {
    
    # map elements in the collection to any other elements or just transforrm
    public static function map(iterable $source, callable $mapper): array;
    
    # filter elements in the collection
    public static function filter(iterable $source, callable $predicate): array;
    
    # alias to filter
    public static function transform(iterable $source, callable $predicate): array;
        
    # remove only elements matching to predicate
    public static function reject(iterable $source, callable $predicate): array;
    
    # get the smallest/lowest/youngest element
    public static function min(iterable $source, callable $firstIsLowerComparator);
    
    # get the biggest/highest/oldest element
    public static function max(iterable $source, callable $firstIsLowerComparator);
    
    # check if collection is empty
    public static function isEmpty(iterable $source): bool;
    
    # check if collection is not empty
    public static function isNotEmpty(iterable $source): bool;
    
    # sort colelction
    public static function sort(iterable $source, callable $biSorter): array;
    
    # count elements in the collection
    public static function count(iterable $source) : int;
    
    # count elements and group by provided keys
    public static function countBy(iterable $source, callable $keyProducer): array;
    
    # reduce collection into 1 element
    public static function reduce(iterable $source, callable $reducer);
    
    # get distinct sub-collection
    public static function distinct(iterable $source, callable $biPredicate): array;
    
    # check if all elements match to criteria
    public static function allMatch(iterable $source, callable $predicate): bool;
    
    # check if any elements match to criteria
    public static function anyMatch(iterable $source, callable $predicate): bool;
    
    # check if every element doesnt match to criteria
    public static function noneMatch(iterable $source, callable $predicate): bool;
    
    # get sub-collection groupped by 
}