Re: [RFC] [Discussion] Add new function `array_group`
| From: | Boro Sitnikovski | Date: | Tue, 30 May 2023 17:24:51 +0000 |
| Subject: | Re: [RFC] [Discussion] Add new function `array_group` | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-120474@lists.php.net to get a copy of this message | ||
Hi,
> On 30.5.2023, at 18:33, Andreas Hennings <andreas@dqxtech.net> wrote:
>
> On Tue, 30 May 2023 at 18:27, Boro Sitnikovski <buritomath@gmail.com> wrote:
>>
>> Hi,
>>
>> Thank you for your thoughts.
>>
>>> I would say the more common desired behavior is the one in your first
>>> example. And even for that we don't have a native function.
>>
>> This Google search might give more insight into the number of discussions about a grouping
>> functionality:
>> https://www.google.com/search?q=php+group+elements+site:stackoverflow.com
>
> All of the examples I looked at are asking for the first kind of
> grouping, that can be implemented as in your first example.
> In all the examples, if two items are equal, they end up in the same group.
>
> In your proposed behavior, equal items can end up in distinct groups
> depending on their original position in the source array.
> I don't see any questions or examples that ask for this.
This is correct, although, if the array is sorted initially (and depending on which operation and
what we want to do), we can still solve the same problem by using equality check.
The idea is that
array_group is more general since it works with operators other than
==, whereas the hashmap approach is only limited to equality check.
A good illustration of this is the increasing subsequences problem, or any other problem of similar
nature.
Here's some more examples:
1. Use array_group to create list of singleton list:
```
$groups = array_group( $arr, function( $p1, $p2 ) {
return false;
} );
```
(This can also be achieved with array_map returning [ $x ])
2. Distinct groups for consecutive positive and negative elements
```
$arr = [-1,2,-3,-4,2,1,2,-3,1,1,2];
$groups = array_group( $arr, function( $p1, $p2 ) {
return ($p1 > 0) == ($p2 > 0);
} );
```
This produces [[-1],[2],[-3,-4],[2,1,2],[-3],[1,1,2]], so we can easily capture the
groups of highs/lows for example.
3. Group sentences (similar to explode, but still different)
```
$arr = "Hello, PHP. Good to see you.";
$groups = array_group( str_split( $arr ), function( $p1, $p2 ) {
return '.' !== $p1;
} );
$groups = array_map( 'join', $groups );
```
Producing [ "Hello, PHP.", " Good to see you." ].
4. Grouping book sections
```
$book_sections = [ '1.0', '1.1', '1.2', '2.0',
'2.1', '3.0', '3.1' ];
$groups = array_group( $book_sections, function( $p1, $p2 ) {
return $p1[0] === $p2[0];
} );
```
Producing [ [ '1.0', '1.1', '1.2' ], [ '2.0',
'2.1'], [ '3.0', '3.1' ] ]
and so on...
Basically, it's a very general utility :)
Best,
Boro
>
> -- Andreas
>
>>
>>> Your behavior can be implemented in userland like so:
>>> https://3v4l.org/epvHm
>>
>> Correct, but then again, we can also implement
>> array_map/array_filter/etc. in
>> userland :)
>>
>>> I think you need to make a case as to why the behavior you describe
>>> justifies a native function.
>>
>> Similar to my previous answer, but also in general - ease of access and also performance.
>>
>>> E.g. if you find a lot of public php code that does this kind of grouping.
>>>
>>> I personally suspect it is not that common.
>>>
>>> Cheers
>>> Andreas
>>>
>>>
>>> On Tue, 30 May 2023 at 17:08, Boro Sitnikovski <buritomath@gmail.com> wrote:
>>>>
>>>> Hey,
>>>>
>>>> Thanks for the suggestion.
>>>>
>>>> For the previous case in the code, I added these in a Gist to not clutter here too
>>>> much:
>>>>
>>>> 1. The first example corresponds to
>>>> https://gist.github.com/bor0/b5f449bfe85440d96abd933b9f03b310#file-test_manual_group-php
>>>> 2. The second example corresponds to
>>>> https://gist.github.com/bor0/b5f449bfe85440d96abd933b9f03b310#file-test_array_group-php
>>>> 3. Another example, addressing the problem of increasing subsequences is very
>>>> simple with array_group:
>>>> https://gist.github.com/bor0/b5f449bfe85440d96abd933b9f03b310#file-test_array_incr_subseqs-php
>>>>
>>>> Best,
>>>>
>>>> Boro
>>>>
>>>>> On 30.5.2023, at 16:57, Andreas Hennings <andreas@dqxtech.net> wrote:
>>>>>
>>>>> Hello Boro,
>>>>> I think you should include the "expected result" in your code
>>>>> examples.
>>>>> Maybe this is in your patch file, but I don't think we want to look at
>>>>> that for discussion.
>>>>>
>>>>> Cheers
>>>>> Andreas
>>>>>
>>>>> On Tue, 30 May 2023 at 13:35, Boro Sitnikovski <buritomath@gmail.com>
>>>>> wrote:
>>>>>>
>>>>>> Hello all,
>>>>>>
>>>>>> As per the How To Create an RFC instructions, I am sending this e-mail in
>>>>>> order to get your feedback on my proposal.
>>>>>>
>>>>>> I propose introducing a function to PHP core named
>>>>>> array_group. This function takes an array and a function and returns
>>>>>> an array that contains arrays - groups of consecutive elements. This is very similar to
>>>>>> Haskell's groupBy function.
>>>>>>
>>>>>> For some background as to why - usually, when people want to do grouping in
>>>>>> PHP, they use hash maps, so something like:
>>>>>>
>>>>>> ```
>>>>>> <?php
>>>>>> $array = [
>>>>>> [ 'id' => 1, 'value' => 'foo' ],
>>>>>> [ 'id' => 1, 'value' => 'bar' ],
>>>>>> [ 'id' => 2, 'value' => 'baz' ],
>>>>>> ];
>>>>>>
>>>>>> $groups = [];
>>>>>> foreach ( $array as $element ) {
>>>>>> $groups[ $element['id'] ][] = $element;
>>>>>> }
>>>>>>
>>>>>> var_dump( $groups );
>>>>>> ```
>>>>>>
>>>>>> This can now be achieved as follows (not preserving keys):
>>>>>>
>>>>>> ```
>>>>>> <?php
>>>>>> $array = [
>>>>>> [ 'id' => 1, 'value' => 'foo' ],
>>>>>> [ 'id' => 1, 'value' => 'bar' ],
>>>>>> [ 'id' => 2, 'value' => 'baz' ],
>>>>>> ];
>>>>>>
>>>>>> $groups = array_group( $array, function( $a, $b ) {
>>>>>> return $a['id'] == $b['id'];
>>>>>> } );
>>>>>> ```
>>>>>>
>>>>>> The disadvantage of the first approach is that we are only limited to using
>>>>>> equality check, and we cannot group by, say, < or other
>>>>>> functions.
>>>>>> Similarly, the advantage of the first approach is that the keys are
>>>>>> preserved, and elements needn't be consecutive.
>>>>>>
>>>>>> In any case, I think a utility function such as
>>>>>> array_group will be widely useful.
>>>>>>
>>>>>> Please find attached a patch with a proposed implementation. Curious about
>>>>>> your feedback.
>>>>>>
>>>>>> Best,
>>>>>>
>>>>>> Boro Sitnikovski
>>>>>>
>>>>
>>