Skip to content

Commit a98b04f

Browse files
committed
Add Sequence::except() to return a sequence with values except those passed
1 parent 6784eef commit a98b04f

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

src/main/php/util/data/Sequence.class.php

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88
* Sequences API for PHP
99
*
1010
* @test util.data.unittest.SequenceTest
11-
* @test util.data.unittest.SequenceCreationTest
12-
* @test util.data.unittest.SequenceSortingTest
1311
* @test util.data.unittest.SequenceCollectionTest
1412
* @test util.data.unittest.SequenceConcatTest
13+
* @test util.data.unittest.SequenceCreationTest
14+
* @test util.data.unittest.SequenceExceptTest
1515
* @test util.data.unittest.SequenceFilteringTest
1616
* @test util.data.unittest.SequenceFlatteningTest
1717
* @test util.data.unittest.SequenceIteratorTest
1818
* @test util.data.unittest.SequenceMappingTest
1919
* @test util.data.unittest.SequenceReductionTest
2020
* @test util.data.unittest.SequenceResultSetTest
2121
* @test util.data.unittest.SequenceSkipTest
22+
* @test util.data.unittest.SequenceSortingTest
2223
* @test util.data.unittest.SequenceWindowTest
2324
*/
2425
class Sequence implements Value, IteratorAggregate {
@@ -427,6 +428,36 @@ public function map($function) {
427428
return new self($f());
428429
}
429430

431+
/**
432+
* Returns a new sequence yielding values except for those passed to this
433+
* method. Uses `util.Objects::equal()` to compare values.
434+
*
435+
* @param var... $values
436+
* @return self
437+
*/
438+
public function except(... $values) {
439+
if (empty($values)) {
440+
return $this;
441+
} else if (1 === sizeof($values)) {
442+
$value= current($values);
443+
$f= function() use($value) {
444+
foreach ($this->elements as $key => $element) {
445+
Objects::equal($element, $value) || yield $key => $element;
446+
}
447+
};
448+
} else {
449+
$f= function() use($values) {
450+
foreach ($this->elements as $key => $element) {
451+
foreach ($values as $value) {
452+
if (Objects::equal($element, $value)) continue 2;
453+
}
454+
yield $key => $element;
455+
}
456+
};
457+
}
458+
return new self($f());
459+
}
460+
430461
/**
431462
* Combines values from this sequence with a given enumerable value,
432463
* optionally using a given transformation function.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php namespace util\data\unittest;
2+
3+
use test\{Assert, Test};
4+
use util\data\Sequence;
5+
6+
class SequenceExceptTest extends AbstractSequenceTest {
7+
8+
#[Test]
9+
public function except_empty() {
10+
$this->assertSequence([1, 2, 3, 4], Sequence::of([1, 2, 3, 4])->except());
11+
}
12+
13+
#[Test]
14+
public function except_one() {
15+
$this->assertSequence([1, 2, 4], Sequence::of([1, 2, 3, 4])->except(3));
16+
}
17+
18+
#[Test]
19+
public function except_multiple() {
20+
$this->assertSequence([1, 3], Sequence::of([1, 2, 3, 4])->except(2, 4));
21+
}
22+
23+
#[Test]
24+
public function except_varargs() {
25+
$this->assertSequence([1, 3], Sequence::of([1, 2, 3, 4])->except(...[2, 4]));
26+
}
27+
28+
#[Test]
29+
public function except_uses_object_comparison() {
30+
$a= new Person(1, 'A');
31+
$b= new Person(2, 'B');
32+
$c= new Person(3, 'C');
33+
34+
$this->assertSequence([$a, $c], Sequence::of([$a, $b, $c])->except(new Person(2, 'B')));
35+
}
36+
37+
#[Test]
38+
public function except_uses_array_comparison() {
39+
$a= ['id' => 1, 'name' => 'A'];
40+
$b= ['id' => 2, 'name' => 'B'];
41+
$c= ['id' => 3, 'name' => 'C'];
42+
43+
$this->assertSequence([$a, $c], Sequence::of([$a, $b, $c])->except(['id' => 2, 'name' => 'B']));
44+
}
45+
}

0 commit comments

Comments
 (0)