Skip to content

Commit db3a5a5

Browse files
authored
Merge pull request #20 from jejung/feature/distinct
introduce distinct function
2 parents a587227 + 8fc02fd commit db3a5a5

2 files changed

Lines changed: 44 additions & 0 deletions

File tree

src/Stream.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,36 @@ public static function rangeFloat(float $start, float $end, float $step = 1): se
9191
return self::range($start, $end, $step);
9292
}
9393

94+
/**
95+
* Returns a new stream containing only unique values from this stream.
96+
*
97+
* By default, objects are compared to their ids (through <code>spl_object_id()</code>), pass
98+
* in a <code>callable $id</code> to change this behavior.
99+
*
100+
* Items are yielded by the order of their first occurrence.
101+
*
102+
* @param callable|null $id can be used to change items identity, by default <code>is_object($item) ? spl_object_id($item) : $item</code> is used.
103+
* @return self
104+
*/
105+
public function distinct(callable $id = null): self {
106+
if (is_null($id)) {
107+
$id = fn ($item) => is_object($item) ? spl_object_id($item) : $item;
108+
}
109+
$generator = function () use ($id) {
110+
$visited = [];
111+
foreach ($this->source_iterator as $item) {
112+
$item_id = $id($item);
113+
if (array_key_exists($item_id, $visited)) {
114+
continue;
115+
}
116+
$visited[$item_id] = true;
117+
yield $item;
118+
}
119+
};
120+
121+
return new self($generator());
122+
}
123+
94124
/**
95125
* Collects all stream elements into an array.
96126
*

test/StreamTest.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77

88
class StreamTest extends TestCase {
99

10+
public function testDistinct() {
11+
$cls = new class () {};
12+
13+
$a = new $cls();
14+
$b = new $cls();
15+
16+
$this->assertEquals([], Stream::of([])->distinct()->collect());
17+
$this->assertEquals([1], Stream::of([1])->distinct()->collect());
18+
$this->assertEquals([1], Stream::of([1, 1])->distinct()->collect());
19+
$this->assertEquals([true, false], Stream::of([true, false])->distinct()->collect());
20+
$this->assertEquals([$a, $b], Stream::of([$a, $b, $a])->distinct()->collect());
21+
$this->assertEquals([true, false], Stream::of([true, false, false, null, 0])->distinct($id=fn ($item) => !$item)->collect());
22+
}
23+
1024
public function testStreamIsCountable(): void {
1125
$this->assertCount(0, Stream::of([]));
1226
$this->assertCount(1, Stream::of(['a']));

0 commit comments

Comments
 (0)