Proposal: Adding an ARRAY_FILTER_REINDEX flag to array_values

php.internals

tyson andre

4 years ago
Hi internals, Currently, array_filter will always return the original keys. This often requires an additional wrapping call of array_values(array_filter(...)) to reindex the keys and return a list. (or applications may not realize there will be gaps in the keys until it causes a bug or unexpected JSON encoding, etc.) PHP is also more memory/time efficient at creating packed arrays than it is at creating associative arrays. What are your thoughts on adding `ARRAY_FILTER_REINDEX`, to ignore the original int/string keys and replace them with `0, 1, 2, ...` ``` php > echo json_encode(array_filter([5,6,7,8], fn($value) => $value % 2 > 0)); {"0":5,"2":7} // proposed flag php > echo json_encode(array_filter([5,6,7,8], fn($value) => $value % 2 > 0, ARRAY_FILTER_REINDEX)); [5,7] ``` https://www.php.net/array_filter already has the `int $mode = 0` which accepts the bit flags `ARRAY_FILTER_USE_KEY` and `ARRAY_FILTER_USE_BOTH` These could be then be combined with the proposed bit flag `ARRAY_FILTER_REINDEX`, e.g. to filter an array based on both the array keys and values, and return a list without gaps. (and if $callback is null, this would return a list containing only the truthy values) Thoughts? Thanks, Tyson

Larry Garfield

4 years ago
On Sun, Sep 19, 2021, at 8:11 AM, tyson andre wrote:
> Hi internals, > > Currently, array_filter will always return the original keys. > This often requires an additional wrapping call of > array_values(array_filter(...)) to reindex the keys and return a list. > (or applications may not realize there will be gaps in the keys until > it causes a bug or unexpected JSON encoding, etc.) > > PHP is also more memory/time efficient at creating packed arrays than > it is at creating associative arrays. > > What are your thoughts on adding `ARRAY_FILTER_REINDEX`, to ignore the > original int/string keys and replace them with `0, 1, 2, ...` > > ``` > php > echo json_encode(array_filter([5,6,7,8], fn($value) => $value % 2 > > 0)); > {"0":5,"2":7} > // proposed flag > php > echo json_encode(array_filter([5,6,7,8], fn($value) => $value % 2 > > 0, ARRAY_FILTER_REINDEX)); > [5,7] > ``` > > https://www.php.net/array_filter already has the `int $mode = 0` which > accepts the bit flags `ARRAY_FILTER_USE_KEY` and `ARRAY_FILTER_USE_BOTH` > These could be then be combined with the proposed bit flag > `ARRAY_FILTER_REINDEX`, e.g. to filter an array based on both the array > keys and values, and return a list without gaps. > (and if $callback is null, this would return a list containing only the > truthy values) > > Thoughts? > > Thanks, > Tyson
In cases where I do want it reindexed, the existing array_values() is fine in most cases. Creating small, purpose-built tools that are easily composed is generally the right strategy. The only time I could see a flag being a better alternative is when the memory difference would be huge. Do we have a sense for how much of a memory difference we'd be looking at by combining it into a single operation? (There's also the grossness of nesting functions inside each other, but the answer to that is pipes, not more flags.) --Larry Garfield

Peter Bowyer

4 years ago
On Sun, 19 Sept 2021 at 14:12, tyson andre <tysonandre775@hotmail.com> wrote:
> What are your thoughts on adding `ARRAY_FILTER_REINDEX`, to ignore the > original int/string keys and replace them with `0, 1, 2, ...` >
If it's measurably faster/more memory efficient than array_values(array_filter(...)) across a range of array sizes, I'm strongly in favour as I write this a lot. Peter

[ ]

4 years ago
Hi, I myself faced such bugs because filter function preserves keys. From my experience it is not that easy to locate bug like this. In my case I rewrote solution in other way than it was originally written. Only later I realized that root cause was array_filter On Sun, Sep 19, 2021, 4:11 PM tyson andre <tysonandre775@hotmail.com> wrote:

Marco Pivetta

4 years ago
On Mon, Sep 20, 2021 at 12:02 PM Eugene Sidelnyk <zsidelnik@gmail.com> wrote:
> From my experience it is not that easy to locate bug like this. >
Heyo, just a tip for you (and others in this thread), but if you use `vimeo/psalm` and declare a `list<T>` for a type, then `array_filter()` that are missing an `array_values()` around it will be caught :) ```php /** @return list<mixed> */ function foo(array $input): array { return array_filter($input); } ``` Will produce: ``` INFO: MixedReturnTypeCoercion - 5:12 - The type 'array<array-key, non-empty-mixed>' is more general than the declared return type 'list<mixed>' for foo ``` See https://psalm.dev/r/f9c51f72c2 Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

Guilliam Xavier

4 years ago
On Sun, Sep 19, 2021 at 3:11 PM tyson andre <tysonandre775@hotmail.com> wrote:
> Hi internals, > > Currently, array_filter will always return the original keys. > This often requires an additional wrapping call of > array_values(array_filter(...)) to reindex the keys and return a list. > (or applications may not realize there will be gaps in the keys until it > causes a bug or unexpected JSON encoding, etc.) >
Hi, This "issue" is not limited to array_filter(), there's also array_unique() and even array_diff()/array_intersect() whose variadic signature doesn't allow to add a flag (I think?)... PS: and array_column() has the opposite issue...
-- Guilliam Xavier