count() < 1; $iterator = self::extractIterator($iterable); $iterator->rewind(); return !$iterator->valid(); } /** * Checks if an item occurs in a collection * * @param iterable $iterable * @param mixed $value * @param bool $strict * @return bool */ public static function contains(iterable $iterable, mixed $value, bool $strict = false): bool { if(is_array($iterable)) return in_array($value, $iterable, $strict); if($strict) { foreach($iterable as $item) if($item === $value) return true; } else { foreach($iterable as $item) if($item == $value) return true; } return false; } /** * Checks if a key occurs in a collection. * * @param iterable $iterable * @param mixed $key * @return bool */ public static function containsKey(iterable $iterable, mixed $key): bool { if(is_array($iterable)) return array_key_exists($key, $iterable); foreach($iterable as $k => $_) if($k === $key) return true; return false; } /** * Retrieves the first key in a collection. * * @param iterable $iterable * @return int|string|null */ public static function firstKey(iterable $iterable): int|string|null { if(is_array($iterable)) return array_key_first($iterable); foreach($iterable as $key => $_) return $key; return null; } /** * Retrieves the last key in a collection. * * @param iterable $iterable * @return int|string|null */ public static function lastKey(iterable $iterable): int|string|null { if(is_array($iterable)) return array_key_last($iterable); $key = null; foreach($iterable as $key => $_); return $key; } /** * Gets the index of a value in a collection. * * @param iterable $iterable * @param mixed $value * @param bool $strict * @return int|string|false */ public static function indexOf( iterable $iterable, mixed $value, bool $strict = false ): int|string|false { if(is_array($iterable)) return array_search($value, $iterable, $strict); if($strict) { foreach($iterable as $key => $item) if($item === $value) return $key; } else { foreach($iterable as $key => $item) if($item == $value) return $key; } return false; } /** * Extracts unique values from a collection. * * @param iterable $iterable * @param int $type * @return array */ public static function unique(iterable $iterable, int $type = self::UNIQUE_VALUE): array { if(is_array($iterable)) return array_unique($iterable, $type); // can probably be replicated better than this $items = []; foreach($iterable as $key => $item) $items[$key] = $item; return array_unique($items, $type); } /** * Takes values from a collection and discards the keys. * * @param iterable $iterable * @return array */ public static function reflow(iterable $iterable): array { if(is_array($iterable)) return array_values($iterable); $items = []; foreach($iterable as $item) $items[] = $item; return $items; } /** * Puts a collection in reverse order. * * @param iterable $iterable * @return array */ public static function reverse(iterable $iterable): array { if(is_array($iterable)) return array_reverse($iterable); $items = []; foreach($iterable as $key => $item) $items[$key] = $item; return array_reverse($items); } /** * Merges two collections. * * @param iterable $iterable1 * @param iterable $iterable2 * @return array */ public static function merge(iterable $iterable1, iterable $iterable2): array { return array_merge(self::toArray($iterable1), self::toArray($iterable2)); } /** * Sorts a collection according to a comparer. * * @param iterable $iterable * @param callable $comparer * @return array */ public static function sort(iterable $iterable, callable $comparer): array { if(is_array($iterable)) { usort($iterable, $comparer); return $iterable; } $items = []; foreach($iterable as $key => $item) $items[$key] = $item; usort($items, $comparer); return $items; } /** * Takes a subsection of a collection. * * @param iterable $iterable * @param int $offset * @param int|null $length * @return array */ public static function slice(iterable $iterable, int $offset, int|null $length = null): array { if(is_array($iterable)) return array_slice($iterable, $offset, $length); $items = []; foreach($iterable as $key => $item) $items[$key] = $item; return array_slice($items, $offset, $length); } public static function toArray(iterable $iterable): array { if(is_array($iterable)) return $iterable; $items = []; foreach($iterable as $key => $item) $items[$key] = $item; return $items; } /** * Checks if any value in the collection matches a given predicate. * * @param iterable $iterable * @param callable $predicate * @return bool */ public static function any(iterable $iterable, callable $predicate): bool { foreach($iterable as $value) if($predicate($value)) return true; return false; } /** * Checks if all values in the collection match a given predicate. * * @param iterable $iterable * @param callable $predicate * @return bool */ public static function all(iterable $iterable, callable $predicate): bool { foreach($iterable as $value) if(!$predicate($value)) return false; return true; } /** * Gets a subset of a collection based on a given predicate. * * @param iterable $iterable * @param callable $predicate * @return array */ public static function where(iterable $iterable, callable $predicate): array { $array = []; foreach($iterable as $value) if($predicate($value)) $array[] = $value; return $array; } /** * Gets the first item in a collection that matches a given predicate. * * @param iterable $iterable * @param callable|null $predicate * @return mixed */ public static function first(iterable $iterable, ?callable $predicate = null): mixed { if($predicate === null) { if(is_array($iterable)) { if(empty($iterable)) return null; return $iterable[array_key_first($iterable)]; } foreach($iterable as $value) return $value; return null; } foreach($iterable as $value) if($predicate($value)) return $value; return null; } /** * Gets the last item in a collection that matches a given predicate. * * @param iterable $iterable * @param callable|null $predicate * @return mixed */ public static function last(iterable $iterable, ?callable $predicate = null): mixed { if($predicate === null) { if(is_array($iterable)) { if(empty($iterable)) return null; return $iterable[array_key_last($iterable)]; } $value = null; foreach($iterable as $value); return $value; } $iterable = self::reverse($iterable); foreach($iterable as $value) if($predicate($value)) return $value; return null; } /** * Applies a modifier on a collection. * * @param iterable $iterable * @param callable $selector * @return array */ public static function select(iterable $iterable, callable $selector): array { if(is_array($iterable)) return array_map($selector, $iterable); $array = []; foreach($iterable as $key => $value) $array[] = $selector($value, $key); return $array; } /** * Tries to extract an instance of Iterator from any iterable type. * * @param iterable $iterable * @return Iterator */ public static function extractIterator(iterable &$iterable): Iterator { if($iterable instanceof Iterator) return $iterable; if($iterable instanceof IteratorAggregate) return $iterable->getIterator(); // @phpstan-ignore-line if(is_array($iterable)) return new ArrayIterator($iterable); throw new InvalidArgumentException('$iterable wasn\'t Iterator, IteratorAggregate or array.'); } /** * Checks if two collections are equal in both keys and values. * * @param iterable $iterable1 * @param iterable $iterable2 * @return bool */ public static function sequenceEquals(iterable $iterable1, iterable $iterable2): bool { if(count($iterable1) !== count($iterable2)) return false; $iterator1 = self::extractIterator($iterable1); $iterator2 = self::extractIterator($iterable2); $iterator1->rewind(); $iterator2->rewind(); if(($valid = $iterator1->valid()) !== $iterator2->valid()) return false; while($valid) { if($iterator1->key() !== $iterator2->key()) return false; $c1 = $iterator1->current(); $c2 = $iterator2->current(); if($c1 instanceof IEquatable) { if(!$c1->equals($c2)) return false; } elseif($c2 instanceof IEquatable) { if(!$c2->equals($c1)) return false; } elseif($c1 !== $c2) return false; $iterator1->next(); $iterator2->next(); if(($valid = $iterator1->valid()) !== $iterator2->valid()) return false; } return true; } }