Skip to content

Commit 05a57f5

Browse files
authored
Add tuples() to convert stream to [key, value] tuples (#147)
1 parent e1e4a2b commit 05a57f5

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ All entry points always return an instance of the pipeline.
123123
| `fold()` | Reduces input values to a single value. Defaults to summation. Requires an initial value. | `array_reduce`, `Aggregate`, `Sum` |
124124
| `reduce()` | Alias to `fold()` with a reversed order of arguments. | `array_reduce` |
125125
| `flip()` | Swaps keys and values. | `array_flip` |
126+
| `tuples()` | Converts stream to [key, value] tuples. | |
126127
| `max()` | Finds the highest value. | `max` |
127128
| `min()` | Finds the lowest value. | `min` |
128129
| `count()` | Counts values. Eagerly executed.| `array_count` |

src/Standard.php

+34
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
use function min;
4848
use function mt_getrandmax;
4949
use function mt_rand;
50+
use function array_keys;
5051

5152
/**
5253
* Concrete pipeline with sensible default callbacks.
@@ -1053,6 +1054,39 @@ private static function flipKeysAndValues(iterable $previous): iterable
10531054
}
10541055
}
10551056

1057+
/**
1058+
* @return $this
1059+
*/
1060+
public function tuples()
1061+
{
1062+
if ($this->empty()) {
1063+
// No-op: null.
1064+
return $this;
1065+
}
1066+
1067+
if (is_array($this->pipeline)) {
1068+
$this->pipeline = array_map(
1069+
fn($key, $value) => [$key, $value],
1070+
array_keys($this->pipeline),
1071+
$this->pipeline
1072+
);
1073+
1074+
return $this;
1075+
}
1076+
1077+
1078+
$this->pipeline = self::toTuples($this->pipeline);
1079+
1080+
return $this;
1081+
}
1082+
1083+
private static function toTuples(iterable $previous): iterable
1084+
{
1085+
foreach ($previous as $key => $value) {
1086+
yield [$key, $value];
1087+
}
1088+
}
1089+
10561090
private function feedRunningVariance(Helper\RunningVariance $variance, ?callable $castFunc): self
10571091
{
10581092
if (null === $castFunc) {

tests/TuplesTest.php

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
/**
3+
* Copyright 2017, 2018 Alexey Kopytko <[email protected]>
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace Tests\Pipeline;
21+
22+
use ArrayIterator;
23+
use PHPUnit\Framework\TestCase;
24+
25+
use Pipeline\Standard;
26+
use IteratorIterator;
27+
28+
use function Pipeline\fromArray;
29+
use function round;
30+
use function sqrt;
31+
use function Pipeline\take;
32+
use function Pipeline\map;
33+
34+
/**
35+
* @covers \Pipeline\Standard
36+
*
37+
* @internal
38+
*/
39+
final class TuplesTest extends TestCase
40+
{
41+
public static function provideArrays(): iterable
42+
{
43+
yield 'empty_array' => [[], []];
44+
yield 'basic_key_values' => [['a' => 1, 'b' => 2, 'c' => 3], [['a', 1], ['b', 2], ['c', 3]]];
45+
yield 'numeric_keys' => [[10, 20, 30], [[0, 10], [1, 20], [2, 30]]];
46+
47+
yield 'mixed_keys_values' => [
48+
['name' => 'Alice', 1 => 'Bob'],
49+
[['name', 'Alice'], [1, 'Bob']],
50+
];
51+
52+
yield 'null_values' => [['x' => null, 'y' => null], [['x', null], ['y', null]]];
53+
54+
yield 'empty_string_key' => [['' => 'value'], [['', 'value']]];
55+
56+
yield 'nested_arrays' => [['outer' => ['inner1' => 'value1', 'inner2' => 'value2']], [['outer', ['inner1' => 'value1', 'inner2' => 'value2']]]];
57+
}
58+
59+
public static function provideIterables(): iterable
60+
{
61+
foreach (self::provideArrays() as $name => $item) {
62+
yield $item;
63+
64+
$iteratorItem = $item;
65+
$iteratorItem[0] = new ArrayIterator($iteratorItem[0]);
66+
67+
yield "$name(ArrayIterator)" => $iteratorItem;
68+
69+
$iteratorItem = $item;
70+
$iteratorItem[0] = new IteratorIterator(new ArrayIterator($iteratorItem[0]));
71+
72+
yield "$name(IteratorIterator)" => $iteratorItem;
73+
74+
$iteratorItem = $item;
75+
$iteratorItem[0] = fromArray($iteratorItem[0]);
76+
77+
yield "$name(Pipeline)" => $iteratorItem;
78+
}
79+
80+
yield 'generator' => [map(function () {
81+
yield '1' => 2;
82+
yield '2' => 3;
83+
}), [['1', 2], ['2', 3]]];
84+
}
85+
86+
/**
87+
* @dataProvider provideIterables
88+
*/
89+
public function testTuples(iterable $input, array $expected, bool $preserve_keys = false): void
90+
{
91+
$pipeline = take($input);
92+
93+
$pipeline->tuples();
94+
95+
$this->assertSame(
96+
$expected,
97+
$pipeline->toArray($preserve_keys)
98+
);
99+
}
100+
101+
public function testNoop(): void
102+
{
103+
$pipeline = new Standard();
104+
105+
$pipeline->tuples();
106+
107+
$this->assertSame([], $pipeline->toArray());
108+
}
109+
}

0 commit comments

Comments
 (0)