Iteration primitives using generators

Related tags

Architectural iter
Overview

Iteration primitives using generators

This library implements iteration primitives like map() and filter() using generators. To a large part this serves as a repository for small examples of generator usage, but of course the functions are also practically quite useful.

All functions in this library accept arbitrary iterables, i.e. arrays, traversables, iterators and aggregates, which makes it quite different from functions like array_map() (which only accept arrays) and the SPL iterators (which usually only accept iterators, not even aggregates). The operations are of course lazy.

Install

To install with composer:

composer require nikic/iter

Functionality

A small usage example for the map() and range() functions:

<?php

use iter\func;

require 'path/to/vendor/autoload.php';

$nums = iter\range(1, 10);
$numsTimesTen = iter\map(func\operator('*', 10), $nums);
// => iter(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)

You can find documentation and usage examples for the individual functions in iter.php, here I only list the function signatures as an overview:

Iterator map(callable $function, iterable $iterable)
Iterator mapWithKeys(callable $function, iterable $iterable)
Iterator mapKeys(callable $function, iterable $iterable)
Iterator flatMap(callable $function, iterable $iterable)
Iterator reindex(callable $function, iterable $iterable)
Iterator filter(callable $predicate, iterable $iterable)
Iterator enumerate(iterable $iterable)
Iterator toPairs(iterable $iterable)
Iterator fromPairs(iterable $iterable)
Iterator reductions(callable $function, iterable $iterable, mixed $startValue = null)
Iterator zip(iterable... $iterables)
Iterator zipKeyValue(iterable $keys, iterable $values)
Iterator chain(iterable... $iterables)
Iterator product(iterable... $iterables)
Iterator slice(iterable $iterable, int $start, int $length = INF)
Iterator take(int $num, iterable $iterable)
Iterator drop(int $num, iterable $iterable)
Iterator takeWhile(callable $predicate, iterable $iterable)
Iterator dropWhile(callable $predicate, iterable $iterable)
Iterator keys(iterable $iterable)
Iterator values(iterable $iterable)
Iterator flatten(iterable $iterable, int $levels = INF)
Iterator flip(iterable $iterable)
Iterator chunk(iterable $iterable, int $size, bool $preserveKeys = false)
Iterator chunkWithKeys(iterable $iterable, int $size)
Iterator toIter(iterable $iterable)

Iterator range(number $start, number $end, number $step = null)
Iterator repeat(mixed $value, int $num = INF)
Iterator split(string $separator, string $data)

mixed    reduce(callable $function, iterable $iterable, mixed $startValue = null)
bool     any(callable $predicate, iterable $iterable)
bool     all(callable $predicate, iterable $iterable)
mixed    search(callable $predicate, iterable $iterable)
void     apply(callable $function, iterable $iterable)
string   join(string $separator, iterable $iterable)
int      count(iterable $iterable)
bool     isEmpty(iterable $iterable)
mixed    recurse(callable $function, $iterable)
array    toArray(iterable $iterable)
array    toArrayWithKeys(iterable $iterable)
bool     isIterable($value)

As the functionality is implemented using generators the resulting iterators are by default not rewindable. This library implements additional functionality to allow creating rewindable generators.

You can find documentation for this in iter.rewindable.php, here is just a small usage example of the two main functions:

<?php

use iter\func;

require 'path/to/vendor/autoload.php';

/* Create a rewindable map function which can be used multiple times */
$rewindableMap = iter\makeRewindable('iter\\map');
$res = $rewindableMap(func\operator('*', 3), [1, 2, 3]);

/* Do a rewindable call to map, just once */
$res = iter\callRewindable('iter\\map', func\operator('*', 3), [1, 2, 3]);

The above functions are only useful for your own generators though, for the iter generators rewindable variants are directly provided with an iter\rewindable prefix:

$res = iter\rewindable\map(func\operator('*', 3), [1, 2, 3]);
// etc
Comments
  • Add failing test for slice() iterating too much

    Add failing test for slice() iterating too much

    I was expecting slice() to not iterate further if its limit value is 1 and it already found a value.

    I have added a failing test for if this really is undesired behavior.

    opened by amcsi 14
  • Version 2.0

    Version 2.0

    I'd like to release version 2.0 with PHP version requirement bumped to 7.1 and added type hints.

    Are there any other (breaking) changes that should be done now?

    opened by nikic 12
  • Associate

    Associate

    • Added the associate function to inverse enumerate

    A good example of where this would be useful is if you need to map over the keys and values at the same time:

    $dict = [
        'a' => 1,
        'b' => 2,
        'c' => 3,
    ];
    iter\associate(iter\map(function($tup) {
          return [strtoupper($tup[0], $tup[1] * 2];
    }, iter\enumerate($dict));
    // iter('A' => 2, 'B' => 4, 'C' => 6)
    

    Basically, it provides a much cleaner way to un-enumerate an iterable.

    opened by ragboyjr 12
  • Product combinator generator function

    Product combinator generator function

    Implementation of a product generator function, that returns the cartesian product of 0 or more iterators. The key is a tuple of the iteratables keys, and the value a tuple of the iterables values.

    Example:

    // Returns [[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]
    toArray(product([1, 2], [3, 4, 5]));
    
    opened by nicmart 8
  • Pass key to map function

    Pass key to map function

    Is there any reason for not passing both key and value to the mapKeys and map functions?

    I find myself often wanting to use both even when just changing one.

    Currently one option is to use enumerate, but it makes the code a lot longer than it needs to be.

    opened by SamMousa 7
  • Chunk function to return an Iterator of Iterable chunks

    Chunk function to return an Iterator of Iterable chunks

    Takes an iterable and chunks it into the specified size.

    This function is lazy in that it yields each chunk as a generator which when iterated will yield size times or until the iterator is no longer valid

    Examples:

      iter\chunk([1, 2, 3], 2)
      => iter(iter(1, 2), iter(3))
    
    opened by camspiers 6
  • Added iter\reindex and iter\fn\path

    Added iter\reindex and iter\fn\path

    These two solve a use case which i often have.

    You have a nested associative array like this:

    $securities = [
        [
            'seccode' => 'HT-R-A',
            'isin' => 'HRHT00RA0005',
            'issuer' => [
                'code' => 'HT',
                'name' => 'Hrvatski Telekom d.d.'
            ],
        ],
        [
            'seccode' => 'INGR-O-11CA',
            'isin' => 'HRINGRO11CA1',
            'issuer' => [
                'code' => 'INGR',
                'name' => 'Ingra d.d.'
            ],
        ]
    ];
    

    And you want to iterate over it, but with the key being a value from the array.

    $path = iter\fn\path('issuer', 'code');
    $iter = iter\reindex($securities, $path);
    foreach(iter\keys($iter) as $key) {
        var_dump($key);
    }
    

    This yields:

    string(2) "HT"
    string(4) "INGR"
    
    opened by ihabunek 6
  • PHP 8.1: fix deprecation notices

    PHP 8.1: fix deprecation notices

    A run on PHP 8.1 currently shows:

    PHP Deprecated:  Return type of iter\rewindable\_RewindableGenerator::current() should either be compatible with Iterator::current(): mixed, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/src/iter.rewindable.php on line 123
    PHP Deprecated:  Return type of iter\rewindable\_RewindableGenerator::next() should either be compatible with Iterator::next(): void, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/src/iter.rewindable.php on line 108
    PHP Deprecated:  Return type of iter\rewindable\_RewindableGenerator::key() should either be compatible with Iterator::key(): mixed, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/src/iter.rewindable.php on line 118
    PHP Deprecated:  Return type of iter\rewindable\_RewindableGenerator::valid() should either be compatible with Iterator::valid(): bool, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/src/iter.rewindable.php on line 113
    PHP Deprecated:  Return type of iter\rewindable\_RewindableGenerator::rewind() should either be compatible with Iterator::rewind(): void, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/src/iter.rewindable.php on line 103
    PHP Deprecated:  Return type of iter\_CountableTestDummy::count() should either be compatible with Countable::count(): int, or the #[ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /home/runner/work/iter/iter/test/iterTest.php on line 625
    

    These deprecation notices relate to the Return types for internal methods RFC in PHP 8.1.

    Using the attribute will silence the deprecation notices for now for those methods for which it cannot be added yet (PHP 8.0 mixed). For all other methods, the return type has now been added.

    opened by jrfnl 5
  • Add mapWithKeys()

    Add mapWithKeys()

    #64 caught my eye. I noticed that changing how the existing methods worked would cause issues, so I made a new mapWithKeys() method that passes the iterator key in addition to its value to the callback.

    Here is a copy/paste of the test I wrote for it, to see it in action:

    $mapped = mapWithKeys(func\operator('*'), range(0, 5));
    $this->assertSame([0, 1, 4, 9, 16, 25], toArray($mapped));
    
    $mapped = mapWithKeys(
        function ($v, $k) { return sprintf('%s%s', $k, $v); },
        ['foo' => 'bar', 'bing' => 'baz']
    );
    $this->assertSame(
        ['foo' => 'foobar', 'bing' => 'bingbaz'],
        toArrayWithKeys($mapped)
    );
    
    opened by judahnator 5
  • Feature request for iter\concat

    Feature request for iter\concat

    Similar to the iter\flatten, except it flattens by 1 step. This is very useful in many areas where your generators are yielding arrays and you want that to be unit of data to work with.

    Here's an implementation:

    function concat ($iterable) {
        return iter\reduce(
            function ($chainedIterables, $nextIterable) {
                return iter\chain($chainedIterables, $nextIterable);
            },
            $iterable,
            []
        );
    }
    

    This should be equivalent to a foldl concat implementation in Haskell.

    opened by CMCDragonkai 5
  • Array keys in callable for 'reduce' function

    Array keys in callable for 'reduce' function

    I think will be better if developers will be able to get a key.

    Example:

    use iter as f;
    
    f\reduce(function ($acc, $value, $key) {
        $acc .= sprintf("%s: %s\n", $key, $value);
        return $acc;
    }, $response->headers->all(), '');
    

    Or I can do it otherwise?

    opened by alxsad 5
  • Feature req: something with semantics `array_usearch()` would have if it existed

    Feature req: something with semantics `array_usearch()` would have if it existed

    One super common use case is finding the index at which you need to insert something into an array.

    Built-in array_search() does this if you are looking for an element by exact value or identity. What is dearly missing is a function that returns the key of the first element that matches a user-defined predicate. While it is trivial to write a simple loop, the frequency with which this is needed (particularly when writing complex refactorings using nikic/php-parser) adds up to some cognitive load. It would be great to have a function that DoesJustThat™, and as part of a widely used library too, rather than as a copypaste in every project's myfuncs.php.

    opened by rulatir 2
  • IteratorAggregate not properly handled in toIter

    IteratorAggregate not properly handled in toIter

    The return type of IteratorAggregate::getIterator is Traversable, but toIter assumes the value returned will be of type Iterator. The return type check on toIter therefore fails when getIterator returns another IteratorAggregate.

    opened by jbcollings 0
  • Add a json_encode

    Add a json_encode

    I don't know if it would be relevant or not. Some benchmark might be required to determine whether or not the original json_encode would fail on big arrays with big objects. If so using iterators could become useful. Comparing to the original one there would be the need for special const such as FORCE_OBJECT(which already exists) and a FORCE_LIST

    opened by Neirda24 2
  • Function proposal - at/get()

    Function proposal - at/get()

    We have a use case where we need to get a value by its index.

    In that sense, I'd like to suggest introducing a function at/get(iterable $iterable, int $index) : ?int that takes an iterable and returns the item at the specified index.

    I'll be glad to provide a PR if welcome.

    opened by marcospassos 2
Releases(v2.2.0)
  • v2.2.0(Aug 2, 2021)

  • v2.1.0(Sep 19, 2020)

    • Added iter\slice() method (#80). This works like explode() but produces an iterator.
    • Added iter\mapWithKeys() method (#81). This works like iter\map() but also passes keys as second parameter to the callable.
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(May 30, 2019)

    This release makes iter compatible with PHP 7.4 by renaming the iter\fn namespace to iter\func.

    • PHP >= 7.1 is now required. Functions are annotated with iterable types. (#52)
    • The iter\fn namespace has been renamed to iter\func. This is necessary for PHP 7.4 compatibility. (#79)
    • Default $preserveKeys = false in chunk() and add chunkWithKeys() function.
    • Avoid advancing by one additional iteration in slice(). (#75)
    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Nov 10, 2017)

  • v1.5.0(Apr 26, 2017)

  • v1.4.0(Sep 27, 2016)

    • Fixed infinite loop when iter\zip() is called without arguments.
    • Added additional error checks for various "length" and "count" parameters (usually disallowing negative numbers).
    • The iter\flatten() function now preserves keys.
    • Added an iter\recurse() function. Example use is iter\recurse('iter\toArray', $data) which will recursively convert an iterator to array.
    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Oct 21, 2015)

    • Added Iterator iter\product(...$iterables):
      Returns the cartesian product iterator of the passed iterators. (#25)
    • Added bool iter\isIterable(mixed $value):
      Returns whether the value is an array or Traversable.
    • Added $key parameter to the callback of reduce() and reductions(). (#28)
    • Added support for <=> to fn\operator(). It is also supported on PHP versions that do not natively provide a <=> operator.
    • All functions now validate that inputs are iterables.
    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Mar 8, 2015)

    • Added new iter functions:
      • mixed search(callable $predicate, iterable $iterable):
        Returns the first value from $iterable which satisfies $predicate, or null if no such element exists.
      • Iterator reductions(callable $function, iterable $iterable, mixed $startValue = null):
        Returns an iterator which contains the intermediate values produced by applying a reduction function to an iterator. Can for example be used to compute cumulative sums.
    • Added support for the power operator (**) to iter\fn\operator(). Support is available also on older PHP versions which do not have an actual ** operator.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Mar 27, 2014)

    Added iter functions:

    • Iterator mapKeys(callable $function, iterable $iterable)
    • Iterator reindex(callable $function, iterable $iterable)
    • Iterator chunk(iterable $iterable, int $size)
    • Iterator flip(iterable $iterable)
    • string join(string $separator, iterable $iterable)

    Added iter\fn functions:

    • function nested_index(...$indices)
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jan 7, 2014)

Owner
Nikita Popov
Nikita Popov
This is a port of the original WireGuard UI bits as implemented by Netgate in pfSense 2.5.0 to a package suitable for rapid iteration and more frequent updating on future releases of pfSense.

This is a port of the original WireGuard*** UI bits as implemented by Netgate in pfSense 2.5.0 to a package suitable for sideloading and more frequent updating on future releases of pfSense. This also includes some improvments such as a proper status page (found under Status / WireGuard Status) and improved assigned interface handling.

R. Christian McDonald 195 Dec 23, 2022
Primitives for functional programming in PHP

Functional PHP: Functional primitives for PHP NOTE: functional-php used to come with a C extension that implemented most of the functions natively. As

Lars Strojny 1.9k Jan 3, 2023
Dictionary of attack patterns and primitives for black-box application fault injection and resource discovery.

FuzzDB was created to increase the likelihood of finding application security vulnerabilities through dynamic application security testing. It's the f

FuzzDB Project 7.1k Dec 27, 2022
🐼 Framework agnostic package using asynchronous HTTP requests and PHP generators to load paginated items of JSON APIs into Laravel lazy collections.

Framework agnostic package using asynchronous HTTP requests and generators to load paginated items of JSON APIs into Laravel lazy collections.

Andrea Marco Sartori 61 Dec 3, 2022
This package extends the core file generators that are included with Laravel 5

Extended Migration Generators for Laravel 6, 7 and 8 Easily define the migration schema right in your make:migration command. The new commands this pa

Laracasts 2.4k Dec 29, 2022
A collection of generators for Lumen and Laravel 5.

Lumen generators A collection of generators for Lumen and Laravel 5. Contents Why ? Installation Quick Usage Detailed Usage Model Generator Migration

Amine Ben hammou 349 Mar 24, 2022
Generate form validators for Laravel: an extension of way/generators

Laravel Form Validator Contents Introduction Installation Usage Example Tests Introduction After using Jeffrey Way's Generator and his Validator packa

John Evans 6 Jan 14, 2022
Rapidly speed up your Laravel workflow with generators

Fast Workflow in Laravel With Custom Generators This Laravel package provides a variety of generators to speed up your development process. These gene

Jeffrey Way 22 Oct 28, 2022
Laracademy Generators - is a tool set that helps speed up the development process of a Laravel application.

Laracademy Generators Laracademy Generators - is a tool set that helps speed up the development process of a Laravel application. Author(s): Laracadem

Laracademy 320 Dec 24, 2022
Laravel CRUD Generator This Generator package provides various generators like CRUD, API, Controller, Model, Migration, View for your painless development of your applications.

Laravel CRUD Generator This Generator package provides various generators like CRUD, API, Controller, Model, Migration, View for your painless develop

AppzCoder 1.3k Jan 2, 2023
Laravel File Generators with config and publishable stubs

Laravel File Generators Custom Laravel File Generators with a config file and publishable stubs. You can publish the stubs. You can add your own stubs

Ben-Piet O'Callaghan 116 Oct 29, 2022
Apliquei os conceitos de Generators e Fibers separadamente para ler um arquivo de 120MB sem consumir toda a memória

Big File Challenge Este desafio foi proposto pelo Zanfranceschi Você pode ver a proposta do desafio aqui ou então pelo Twitter Para a implementação da

Nicolas Pereira 15 Oct 5, 2022
Yii2 Gii Extended templates and generators

model template with TimestampBehavior and BlameableBehavior according to columns

潘文斌 1 Feb 12, 2020
A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API.

PageMjmlToHtml A module allowing you to write your Processwire template using MJML and get a converted HTML output using MJML API. This is considered

Romain Cazier 7 Oct 5, 2022
This repository demonstrates exemplary implementation of chat using HTTP and Websocket servers in PHP using Kraken Framework components.

This repository demonstrates exemplary implementation of chat using HTTP and Websocket servers in PHP using Kraken Framework components.

Kraken 48 Aug 11, 2021
A research raw data repository for researchers of Arba Minch University built using Codeigniter which follows MVC architecture. The front-end is build using Bootstrap.

Arba Minch University Dataset Repository This system is a research dataset repository for Arba Minch University researchers and is build using Codeign

Wuletaw Wonte 8 Jul 1, 2022
Backend application using Laravel 9.x REST APIs for games topup from digiflazz.com and payment gateway using xendit.co

TOPUP - Laravel 9.x REST API Documentation is still on progress. For now, you can fork this postman collection Installation Clone this project git clo

Muhammad Athhar Kautsar 46 Dec 17, 2022
This PHP library will help you to work with your Pinterest account without using any API account credentials.

Pinterest Bot for PHP A PHP library to help you work with your Pinterest account without API credentials. The Pinterest API is painful: receiving an a

Sergey Zhuk 414 Nov 21, 2022
Cache slam defense using a semaphore to prevent dogpile effect.

metaphore PHP cache slam defense using a semaphore to prevent dogpile effect (aka clobbering updates, stampending herd or Slashdot effect). Problem: t

Przemek Sobstel 102 Sep 28, 2022