New IterTools Functionality Discussion
This thread is for discussion new functionality to implement in IterTools. Please reply with suggestions for new functionality.
Here are some of the functions I am considering implementing. Some are more useful than others.
Single Iteration
Skip
Skip the first n elements in the iterable.
public static function skip(iterable $data, int $n): \Generator
Shuffle
Shuffle the elements in the iterable.
public static function shuffle(iterable $data): \Generator
Note: More useful in a Stream than standalone function.
Filter RegEx
Filter for elements where the regular expression matches.
public static function filterRegEx(iterable $data, string $regex): \Generator
Permutations
All permutations of size $length.
public static function permutations(iterable $data, int $length) \Generator
Combinations
All combinations of size $length.
public static function combinations(iterable $data, int $length) \Generator
Combinations With Replacement
All combinations, with repeated elements, of size $length.
public static function combinationsWithReplacement(iterable $data, int $length) \Generator
Multi
Unzip
Reverse of zip. Ex: ['a', 1], ['b', 2], ['c', 3] => ['a', 'b', 'c'], [1, 2, 3]
public static function unzip(...iterable $iterables): array
Reduce
To Random Value
Reduce the iterable to any random value in the iterable.
public static function toRandomValue(iterable $data): mixed
Note: More useful in a Stream than standalone function.
To Nth
Reduce the iterable to the value at the nth position.
public static function toNth(iterable $data): mixed
Note: More useful in a Stream than standalone function.
To Frequencies
Reduce the iterable to a frequency distribution showing how often each different value in the data occurs.
public static function toFrequencies(iterable $data): array
Note: MathPHP has this functionality. Maybe outside the scope for IterTools.
To Summary Stats
Reduce the iterable (of numbers) to a five-number summary.
public static function toSummaryStats(iterable $data): array
Note: MathPHP has this functionality. Maybe outside the scope for IterTools.
Summary
Not All Match
True if not all the elements are true according to the predicate.
public static function notAllMatch(iterable $data, callable $predicate): bool
Is Empty
True if the iterable is empty.
public static function isEmpty(iterable $data): bool
Note: More useful in a Stream than standalone function.
All Unique
True if all elements of the iterable are unique values.
public static function allUnique(iterable $data): bool
All Equal
True if all elements of the iterable are equal.
public static funcion allEqual(iterable $data): bool
Note: Consider maybe adding a strict parameter, or alternate method allSame.
Set
Union
Difference
CartesianProduct
Transform
Distribute
Distribute the elements of the iterable evenly into n smaller iterables. Ex: [1, 2, 3, 4], 2 => [1, 3], [2, 4]
public static function distribute(iterable $data, int $n): array
Divide
Divide the elements of the iterable evenly into n smaller iterables, maintaining order. Ex: [1, 2, 3, 4], 2 => [1, 2], [3, 4]
public static function divide(iterable $data, int $n): array
Stream
Peek
Peek at each element in between other Stream operations to do some action without modifying the stream. Useful for debugging purposes.
public function peek(callable $action): Stream
It might be useful to also add pre-built peaks:
-
peakPrint -
peekPrintR
Example usage:
Stream::of($someData)
->map($someFunction)
->filter($anotherFunction)
->peakPrint() // Added for debugging during development to see what is going on
->toAverage()
FYI: @Smoren.
Hi @markrogoyski,
Thank you very much for this topic! There are great ideas here and I'll start to implement some of them.
For the beginning I'll take peek(), if you don't mind (UPD: I've added PR with peek methods implementation: https://github.com/markrogoyski/itertools-php/pull/40).
BTW, what about adding $offset param into skip() method to start skipping elements not from the beginning of an iterable?
public static function skip(iterable $data, int $count, int $offset = 0): \Generator
foreach (Single::skip([1, 2, 3, 4, 5, 6, 7], 3, 2) as $item) {
// 1, 2, 6, 7
}
Hi @Smoren,
For skip, I think as long as the offset is optional and defaults to 0 then that works.
Thanks, @markrogoyski, so the next method I'll implement is skip().
UPD: I've added PR https://github.com/markrogoyski/itertools-php/pull/41 with functionality of skip().
Hi @markrogoyski,
What do you think about implementation of subslices()?
foreach (Single::subslices([1, 2, 3] as $slice) {
// [1], [2], [3], [1, 2], [2, 3], [1, 2, 3]
}
BTW: I think it would be nice to have implemented method names ~~strikethrough~~ in this thread.
Hi @markrogoyski,
There is iter package.
What do you think about implementing some methods which are implemented in iter but missing in IterTools PHP?
Here is a comparison:
Hi @markrogoyski,
I've implemented some methods from this topic:
-
Reduce::toRandomValue()(https://github.com/markrogoyski/itertools-php/pull/42); -
Summary::isEmpty()(https://github.com/markrogoyski/itertools-php/pull/43).
Hi @markrogoyski,
I've added and tested Summary::allUnique() method (https://github.com/markrogoyski/itertools-php/pull/44).
Hi @markrogoyski,
I've added and tested Set::union() method (https://github.com/markrogoyski/itertools-php/pull/45).
Hi @markrogoyski,
I've added and tested Reduce::toNth() method (https://github.com/markrogoyski/itertools-php/pull/47).
Hi @markrogoyski,
What do you think about the implementation of zipFilled() function in IterTools PHP like I have done it in IterTools TS?
Hi @Smoren,
I made a choice to not add a fill variable to zipLongest because it would have to be the first parameter, and even if you don't want a filler, you'd have to add that variable.
Interestingly, in PHP 8.1, you can have a named parameter after unpacking a variadic parameter, so I think you could do something like:
Multi::zipLongest($iter1, $iter2, fillValue: 'filler');
where the method signature is:
public function zipLongest(iterable ...$iterables, $fillValue = null);
Then it behaves and sort of looks like how you'd do it in Python.
Right now 7.4 is the minimum version. One option is to just wait a couple years and when I bump up the minimum version to something >= 8.1, then add it to zipLongest. Another option is to do like you suggest and implement a separate function like zipFilled.
Probably simplest to implement zipFilled as it keeps the interface to zipLongest simple.