Skip to content

Commit f08c58f

Browse files
authored
Merge pull request #49 from decole/feature/support-min-collection
Add support for min and minBy to collections
2 parents 8491933 + 54c0706 commit f08c58f

File tree

8 files changed

+203
-3
lines changed

8 files changed

+203
-3
lines changed

src/Fp/Collections/ArrayList.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
use Fp\Operations\MapValuesOperation;
3131
use Fp\Operations\MaxByElementOperation;
3232
use Fp\Operations\MaxElementOperation;
33+
use Fp\Operations\MinByElementOperation;
34+
use Fp\Operations\MinElementOperation;
3335
use Fp\Operations\MkStringOperation;
3436
use Fp\Operations\PrependedAllOperation;
3537
use Fp\Operations\PrependedOperation;
@@ -627,4 +629,23 @@ public function maxBy(callable $callback): Option
627629
{
628630
return MaxByElementOperation::of($this->getIterator())($callback);
629631
}
632+
633+
/**
634+
* @inheritDoc
635+
* @return Option<TV>
636+
*/
637+
public function min(): Option
638+
{
639+
return MinElementOperation::of($this->getIterator())();
640+
}
641+
642+
/**
643+
* @inheritDoc
644+
* @psalm-param callable(TV): mixed $callback
645+
* @return Option<TV>
646+
*/
647+
public function minBy(callable $callback): Option
648+
{
649+
return MinByElementOperation::of($this->getIterator())($callback);
650+
}
630651
}

src/Fp/Collections/LinkedList.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
use Fp\Operations\MapValuesOperation;
3232
use Fp\Operations\MaxByElementOperation;
3333
use Fp\Operations\MaxElementOperation;
34+
use Fp\Operations\MinByElementOperation;
35+
use Fp\Operations\MinElementOperation;
3436
use Fp\Operations\MkStringOperation;
3537
use Fp\Operations\PrependedAllOperation;
3638
use Fp\Operations\ReduceOperation;
@@ -639,4 +641,23 @@ public function maxBy(callable $callback): Option
639641
{
640642
return MaxByElementOperation::of($this->getIterator())($callback);
641643
}
644+
645+
/**
646+
* @inheritDoc
647+
* @return Option<TV>
648+
*/
649+
public function min(): Option
650+
{
651+
return MinElementOperation::of($this->getIterator())();
652+
}
653+
654+
/**
655+
* @inheritDoc
656+
* @psalm-param callable(TV): mixed $callback
657+
* @return Option<TV>
658+
*/
659+
public function minBy(callable $callback): Option
660+
{
661+
return MinByElementOperation::of($this->getIterator())($callback);
662+
}
642663
}

src/Fp/Collections/SeqTerminalOps.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,11 +301,36 @@ public function max(): Option;
301301
*
302302
* ```php
303303
* >>> LinkedList::collect([new Foo(1), new Bar(6), new Foo(2)])->maxBy(fn(Foo $foo) => $foo->a)->get();
304-
* => 6
304+
* => Bar(6)
305305
* ```
306306
*
307307
* @psalm-param callable(TV): mixed $callback
308308
* @psalm-return Option<TV>
309309
*/
310310
public function maxBy(callable $callback): Option;
311+
312+
/**
313+
* Returns the minimum value from collection
314+
*
315+
* ```php
316+
* >>> LinkedList::collect([1, 4, 2])->min()->get();
317+
* => 1
318+
* ```
319+
*
320+
* @psalm-return Option<TV>
321+
*/
322+
public function min(): Option;
323+
324+
/**
325+
* Returns the minimum value from collection by iterating each element using the callback
326+
*
327+
* ```php
328+
* >>> LinkedList::collect([new Foo(1), new Bar(6), new Foo(2)])->minBy(fn(Foo $foo) => $foo->a)->get();
329+
* => Foo(1)
330+
* ```
331+
*
332+
* @psalm-param callable(TV): mixed $callback
333+
* @psalm-return Option<TV>
334+
*/
335+
public function minBy(callable $callback): Option;
311336
}

src/Fp/Operations/MaxByElementOperation.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,4 @@ public function __invoke(callable $by): Option
3232

3333
return FirstOperation::of($gen)();
3434
}
35-
3635
}

src/Fp/Operations/MaxElementOperation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,4 @@ public function __invoke(): Option
2525

2626
return Option::fromNullable(!empty($list) ? max($list) : null);
2727
}
28-
}
28+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Fp\Operations;
6+
7+
use Fp\Functional\Option\Option;
8+
9+
/**
10+
* @psalm-immutable
11+
* @template TK
12+
* @template TV
13+
* @extends AbstractOperation<TK, TV>
14+
*/
15+
class MinByElementOperation extends AbstractOperation
16+
{
17+
/**
18+
* @psalm-param callable(TV): mixed $by
19+
* @return Option<TV>
20+
*/
21+
public function __invoke(callable $by): Option
22+
{
23+
$f =
24+
/**
25+
* @param TV $r
26+
* @param TV $l
27+
* @return int
28+
*/
29+
fn(mixed $r, mixed $l): int => $by($r) <=> $by($l);
30+
31+
$gen = SortedOperation::of($this->gen)($f);
32+
33+
return FirstOperation::of($gen)();
34+
}
35+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Fp\Operations;
6+
7+
use Fp\Functional\Option\Option;
8+
use function Fp\Cast\asList;
9+
10+
/**
11+
* @psalm-immutable
12+
* @template TK
13+
* @template TV
14+
* @extends AbstractOperation<TK, TV>
15+
*/
16+
class MinElementOperation extends AbstractOperation
17+
{
18+
/**
19+
* @return Option<TV>
20+
*/
21+
public function __invoke(): Option
22+
{
23+
$list = asList($this->gen);
24+
25+
return Option::fromNullable(!empty($list) ? min($list) : null);
26+
}
27+
}

tests/Runtime/Interfaces/Seq/SeqOpsTest.php

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,4 +657,76 @@ public function testMaxByInEmptyCollection(Seq $seq, Option $option): void
657657
{
658658
$this->assertEquals($option, $seq->maxBy(fn(Foo $foo) => $foo->a));
659659
}
660+
661+
public function provideTestMinNotEmptyCollections(): Generator
662+
{
663+
yield ArrayList::class => [ArrayList::collect([3, 7, 2]), Option::some(2)];
664+
yield LinkedList::class => [LinkedList::collect([9, 1, 2]), Option::some(1)];
665+
}
666+
667+
/**
668+
* @dataProvider provideTestMinNotEmptyCollections
669+
*/
670+
public function testMinInNotEmptyCollection(Seq $seq, Option $option): void
671+
{
672+
$this->assertEquals($option, $seq->min());
673+
}
674+
675+
public function provideTestMinEmptyCollections(): Generator
676+
{
677+
yield ArrayList::class => [ArrayList::collect([]), Option::none()];
678+
yield LinkedList::class => [LinkedList::collect([]), Option::none()];
679+
}
680+
681+
/**
682+
* @dataProvider provideTestMinEmptyCollections
683+
*/
684+
public function testMinInEmptyCollection(Seq $seq, Option $option): void
685+
{
686+
$this->assertEquals($option, $seq->min());
687+
}
688+
689+
public function provideTestMinByNotEmptyCollections(): Generator
690+
{
691+
yield ArrayList::class => [
692+
ArrayList::collect([new Foo(1), new Foo(5), new Foo(2)]),
693+
Option::some(new Foo(1))
694+
];
695+
yield LinkedList::class => [
696+
LinkedList::collect([new Foo(9), new Foo(4), new Foo(2)]),
697+
Option::some(new Foo(2))
698+
];
699+
}
700+
701+
/**
702+
* @param Seq<Foo> $seq
703+
* @param Option<Foo> $option
704+
* @dataProvider provideTestMinByNotEmptyCollections
705+
*/
706+
public function testMinByInNotEmptyCollection(Seq $seq, Option $option): void
707+
{
708+
$this->assertEquals($option, $seq->minBy(fn(Foo $foo) => $foo->a));
709+
}
710+
711+
public function provideTestMinByEmptyCollections(): Generator
712+
{
713+
yield ArrayList::class => [
714+
ArrayList::collect([]),
715+
Option::none()
716+
];
717+
yield LinkedList::class => [
718+
LinkedList::collect([]),
719+
Option::none()
720+
];
721+
}
722+
723+
/**
724+
* @param Seq<Foo> $seq
725+
* @param Option<Foo> $option
726+
* @dataProvider provideTestMinByEmptyCollections
727+
*/
728+
public function testMinByInEmptyCollection(Seq $seq, Option $option): void
729+
{
730+
$this->assertEquals($option, $seq->minBy(fn(Foo $foo) => $foo->a));
731+
}
660732
}

0 commit comments

Comments
 (0)