Skip to content

Commit

Permalink
last() and lastOrNull() operations
Browse files Browse the repository at this point in the history
  • Loading branch information
bradynpoulsen committed Nov 9, 2019
1 parent fc90166 commit 33962cb
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 0 deletions.
30 changes: 30 additions & 0 deletions src/Operations/Nothing.php
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace BradynPoulsen\Sequences\Operations;

/**
* Singleton value to represent a value that MUST NOT be returned by any sequence operation.
*
* @internal
*/
final class Nothing
{
/**
* @var Nothing
*/
private static $instance;

public static function get(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}

private function __construct()
{
}
}
33 changes: 33 additions & 0 deletions src/Operations/Terminal/PredicateSearchingOperations.php
Expand Up @@ -62,4 +62,37 @@ public static function firstOrNull(Sequence $source, ?callable $predicate = null
return null;
}
}

/**
* @see Sequence::last()
*
* @param callable|null $predicate (T) -> bool
*/
public static function last(Sequence $source, ?callable $predicate = null)
{
$lastElement = Nothing::get();
foreach ($source->getIterator() as $element) {
if ($predicate === null || call_user_func($predicate, $element)) {
$lastElement = $element;
}
}
if ($lastElement !== Nothing::get()) {
return $lastElement;
}
throw new UnexpectedValueException("No element matched the given predicate");
}

/**
* @see Sequence::lastOrNull()
*
* @param callable|null $predicate (T) -> bool
*/
public static function lastOrNull(Sequence $source, ?callable $predicate = null)
{
try {
return self::last($source, $predicate);
} catch (UnexpectedValueException $unexpectedValueException) {
return null;
}
}
}
21 changes: 21 additions & 0 deletions src/Sequence.php
Expand Up @@ -359,6 +359,17 @@ public function ifEmpty(callable $supplier): Sequence;
*/
public function indexOf($element): int;

/**
* Returns the last element matching the given $predicate.
*
* @effect terminal
*
* @param callable|null $predicate (T) -> bool
* @return mixed Sequence<T> -> T
* @throws UnexpectedValueException if no elements matched the predicate
*/
public function last(?callable $predicate = null);

/**
* Returns last index of $element, or -1 if this sequence does not contain $element.
*
Expand All @@ -369,6 +380,16 @@ public function indexOf($element): int;
*/
public function lastIndexOf($element): int;

/**
* Returns the last element matching the given $predicate, or null if element was not found.
*
* @effect terminal
*
* @param callable|null $predicate (T) -> bool
* @return mixed Sequence<T> -> T
*/
public function lastOrNull(?callable $predicate = null);

/**
* Returns a sequence containing the results of applying the given $transform function to each element of
* this sequence.
Expand Down
16 changes: 16 additions & 0 deletions src/Traits/TerminalOperationsTrait.php
Expand Up @@ -152,6 +152,14 @@ public function indexOf(Sequence $source, $element): int
return ElementSearchingOperations::indexOf($this, $element);
}

/**
* @see Sequence::last()
*/
public function last(?callable $predicate = null)
{
return PredicateSearchingOperations::last($this, $predicate);
}

/**
* @see Sequence::lastIndexOf()
*/
Expand All @@ -160,6 +168,14 @@ public function lastIndexOf(Sequence $source, $element): int
return ElementSearchingOperations::lastIndexOf($this, $element);
}

/**
* @see Sequence::lastOrNull()
*/
public function lastOrNull(?callable $predicate = null)
{
return PredicateSearchingOperations::lastOrNull($this, $predicate);
}

/**
* @see Sequence::max()
*/
Expand Down

0 comments on commit 33962cb

Please sign in to comment.