itertools-php icon indicating copy to clipboard operation
itertools-php copied to clipboard

New IterTools Functionality Discussion

Open markrogoyski opened this issue 3 years ago • 12 comments

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.

markrogoyski avatar Feb 16 '23 06:02 markrogoyski

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
}

Smoren avatar Feb 16 '23 07:02 Smoren

Hi @Smoren,

For skip, I think as long as the offset is optional and defaults to 0 then that works.

markrogoyski avatar Feb 17 '23 06:02 markrogoyski

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().

Smoren avatar Feb 17 '23 07:02 Smoren

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.

Smoren avatar Feb 17 '23 08:02 Smoren

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:

IterTools PHP iter
Multi::chain chain
Multi::zip zip
Multi::zipEqual -
Multi::zipLongest -
- zipKeyValue
Single::chunkwise chunk
Single::chunkwiseOverlap -
- chunkWithKeys
Single::compress -
Single::compressAssociative -
- drop
Single::dropWhile dropWhile
- enumerate, toPairs (equivalents of each other, but not equivalents of Single::pairwise)
Single::filter filter
Single::filterTrue -
Single::filterFalse -
Single::filterKeys -
Single::flatMap flatMap
Single::flatten flatten
- flip
Single::groupBy -
- keys
Single::limit -
Single::map map
- mapKeys
- mapWithKeys
Single::pairwise -
- product
Single::reindex reindex
Single::repeat repeat
Single::reverse -
- recurse
Single::slice slice
Single::string split
- take
Single::takeWhile takeWhile
Infinite::count range
Infinite::cycle -
Infinite::repeat -
Random::choice -
Random::coinFlip -
Random::number -
Random::percentage -
Random::rockPaperScissors -
Math::runningAverage -
Math::runningDifference -
Math::runningMax -
Math::runningMin -
Math::runningProduct -
Math::runningTotal -
Set::distinct -
Set::intersection -
Set::intersectionCoercive -
Set::partialIntersection -
Set::partialIntersectionCoercive -
Set::symmetricDifference -
Set::symmetricDifferenceCoercive -
Sort::asort -
Sort::sort -
File::readCsv -
File::readLines -
- fromPairs
Transform::tee -
Transform::toArray toArray
Transform::toAssociativeArray toArrayWithKeys
Transform::toIterator toIter
Summary::allMatch all
Summary::anyMatch any
Summary::arePermutations -
Summary::arePermutationsCoercive -
Summary::exactlyN -
- isEmpty
- isIterable
Stream::callForEach apply
Summary::isPartitioned -
Summary::isSorted -
Summary::isReversed -
Summary::noneMatch -
Summary::same -
Summary::sameCount -
- reductions
- search
Reduce::toAverage -
Reduce::toCount count
Reduce::toFirst -
Reduce::toFirstAndLast -
Reduce::toLast -
Reduce::toMax -
Reduce::toMin -
Reduce::toMinMax -
Reduce::toProduct -
Reduce::toRange -
Reduce::toString join
Reduce::toSum -
Reduce::toValue reduce
- values

Smoren avatar Feb 18 '23 18:02 Smoren

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).

Smoren avatar Feb 25 '23 09:02 Smoren

Hi @markrogoyski,

I've added and tested Summary::allUnique() method (https://github.com/markrogoyski/itertools-php/pull/44).

Smoren avatar Mar 01 '23 07:03 Smoren

Hi @markrogoyski,

I've added and tested Set::union() method (https://github.com/markrogoyski/itertools-php/pull/45).

Smoren avatar Mar 02 '23 11:03 Smoren

Hi @markrogoyski,

I've added and tested Reduce::toNth() method (https://github.com/markrogoyski/itertools-php/pull/47).

Smoren avatar Mar 13 '23 13:03 Smoren

Hi @markrogoyski,

What do you think about the implementation of zipFilled() function in IterTools PHP like I have done it in IterTools TS?

Smoren avatar Mar 20 '23 12:03 Smoren

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.

markrogoyski avatar Mar 21 '23 05:03 markrogoyski