/vendor/phpcollection/phpcollection/src/PhpCollection/AbstractSequence.php

https://gitlab.com/cuza/Clinic_Recods · PHP · 360 lines · 223 code · 59 blank · 78 comment · 20 complexity · 840275a4d457c33a7237709dbbce13e6 MD5 · raw file

  1. <?php
  2. /*
  3. * Copyright 2012 Johannes M. Schmitt <schmittjoh@gmail.com>
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace PhpCollection;
  18. use PhpOption\Some;
  19. use PhpOption\None;
  20. use PhpOption\Option;
  21. use OutOfBoundsException;
  22. /**
  23. * A sequence with numerically indexed elements.
  24. *
  25. * This is rawly equivalent to an array with only numeric keys.
  26. * There are no restrictions on how many same values may occur in the sequence.
  27. *
  28. * This sequence is mutable.
  29. *
  30. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  31. */
  32. class AbstractSequence extends AbstractCollection implements \IteratorAggregate, SequenceInterface
  33. {
  34. protected $elements;
  35. /**
  36. * @param array $elements
  37. */
  38. public function __construct(array $elements = array())
  39. {
  40. $this->elements = array_values($elements);
  41. }
  42. public function addSequence(SequenceInterface $seq)
  43. {
  44. $this->addAll($seq->all());
  45. }
  46. public function indexOf($searchedElement)
  47. {
  48. foreach ($this->elements as $i => $element) {
  49. if ($searchedElement === $element) {
  50. return $i;
  51. }
  52. }
  53. return -1;
  54. }
  55. public function lastIndexOf($searchedElement)
  56. {
  57. for ($i=count($this->elements)-1; $i>=0; $i--) {
  58. if ($this->elements[$i] === $searchedElement) {
  59. return $i;
  60. }
  61. }
  62. return -1;
  63. }
  64. public function isDefinedAt($index)
  65. {
  66. return isset($this->elements[$index]);
  67. }
  68. /**
  69. * Returns a filtered sequence.
  70. *
  71. * @param callable $callable receives the element and must return true (= keep) or false (= remove).
  72. *
  73. * @return AbstractSequence
  74. */
  75. public function filter($callable)
  76. {
  77. return $this->filterInternal($callable, true);
  78. }
  79. public function map($callable)
  80. {
  81. $newElements = array();
  82. foreach ($this->elements as $i => $element) {
  83. $newElements[$i] = $callable($element);
  84. }
  85. return $this->createNew($newElements);
  86. }
  87. /**
  88. * Returns a filtered sequence.
  89. *
  90. * @param callable $callable receives the element and must return true (= remove) or false (= keep).
  91. *
  92. * @return AbstractSequence
  93. */
  94. public function filterNot($callable)
  95. {
  96. return $this->filterInternal($callable, false);
  97. }
  98. private function filterInternal($callable, $booleanKeep)
  99. {
  100. $newElements = array();
  101. foreach ($this->elements as $element) {
  102. if ($booleanKeep !== call_user_func($callable, $element)) {
  103. continue;
  104. }
  105. $newElements[] = $element;
  106. }
  107. return $this->createNew($newElements);
  108. }
  109. public function foldLeft($initialValue, $callable)
  110. {
  111. $value = $initialValue;
  112. foreach ($this->elements as $elem) {
  113. $value = call_user_func($callable, $value, $elem);
  114. }
  115. return $value;
  116. }
  117. public function foldRight($initialValue, $callable)
  118. {
  119. $value = $initialValue;
  120. foreach (array_reverse($this->elements) as $elem) {
  121. $value = call_user_func($callable, $elem, $value);
  122. }
  123. return $value;
  124. }
  125. /**
  126. * Finds the first index where the given callable returns true.
  127. *
  128. * @param callable $callable
  129. *
  130. * @return integer the index, or -1 if the predicate is not true for any element.
  131. */
  132. public function indexWhere($callable)
  133. {
  134. foreach ($this->elements as $i => $element) {
  135. if (call_user_func($callable, $element) === true) {
  136. return $i;
  137. }
  138. }
  139. return -1;
  140. }
  141. public function lastIndexWhere($callable)
  142. {
  143. for ($i=count($this->elements)-1; $i>=0; $i--) {
  144. if (call_user_func($callable, $this->elements[$i]) === true) {
  145. return $i;
  146. }
  147. }
  148. return -1;
  149. }
  150. public function last()
  151. {
  152. if (empty($this->elements)) {
  153. return None::create();
  154. }
  155. return new Some(end($this->elements));
  156. }
  157. public function first()
  158. {
  159. if (empty($this->elements)) {
  160. return None::create();
  161. }
  162. return new Some(reset($this->elements));
  163. }
  164. public function indices()
  165. {
  166. return array_keys($this->elements);
  167. }
  168. /**
  169. * Returns an element based on its index (0-based).
  170. *
  171. * @param integer $index
  172. *
  173. * @return T
  174. */
  175. public function get($index)
  176. {
  177. if ( ! isset($this->elements[$index])) {
  178. throw new OutOfBoundsException(sprintf('The index "%s" does not exist in this sequence.', $index));
  179. }
  180. return $this->elements[$index];
  181. }
  182. /**
  183. * Removes the element at the given index, and returns it.
  184. *
  185. * @param int $index
  186. *
  187. * @return T
  188. *
  189. * @throws \OutOfBoundsException If there is no element at the given index.
  190. */
  191. public function remove($index)
  192. {
  193. if ( ! isset($this->elements[$index])) {
  194. throw new OutOfBoundsException(sprintf('The index "%d" is not in the interval [0, %d).', $index, count($this->elements)));
  195. }
  196. $element = $this->elements[$index];
  197. unset($this->elements[$index]);
  198. $this->elements = array_values($this->elements);
  199. return $element;
  200. }
  201. /**
  202. * Updates the element at the given index (0-based).
  203. *
  204. * @param integer $index
  205. * @param T $value
  206. */
  207. public function update($index, $value)
  208. {
  209. if ( ! isset($this->elements[$index])) {
  210. throw new \InvalidArgumentException(sprintf('There is no element at index "%d".', $index));
  211. }
  212. $this->elements[$index] = $value;
  213. }
  214. public function isEmpty()
  215. {
  216. return empty($this->elements);
  217. }
  218. public function all()
  219. {
  220. return $this->elements;
  221. }
  222. public function add($newElement)
  223. {
  224. $this->elements[] = $newElement;
  225. }
  226. public function addAll(array $addedElements)
  227. {
  228. foreach ($addedElements as $newElement) {
  229. $this->elements[] = $newElement;
  230. }
  231. }
  232. public function take($number)
  233. {
  234. if ($number <= 0) {
  235. throw new \InvalidArgumentException(sprintf('$number must be greater than 0, but got %d.', $number));
  236. }
  237. return $this->createNew(array_slice($this->elements, 0, $number));
  238. }
  239. /**
  240. * Extracts element from the head while the passed callable returns true.
  241. *
  242. * @param callable $callable receives elements of this sequence as first argument, and returns true/false.
  243. *
  244. * @return Sequence
  245. */
  246. public function takeWhile($callable)
  247. {
  248. $newElements = array();
  249. for ($i=0,$c=count($this->elements); $i<$c; $i++) {
  250. if (call_user_func($callable, $this->elements[$i]) !== true) {
  251. break;
  252. }
  253. $newElements[] = $this->elements[$i];
  254. }
  255. return $this->createNew($newElements);
  256. }
  257. public function drop($number)
  258. {
  259. if ($number <= 0) {
  260. throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number));
  261. }
  262. return $this->createNew(array_slice($this->elements, $number));
  263. }
  264. public function dropRight($number)
  265. {
  266. if ($number <= 0) {
  267. throw new \InvalidArgumentException(sprintf('The number must be greater than 0, but got %d.', $number));
  268. }
  269. return $this->createNew(array_slice($this->elements, 0, -1 * $number));
  270. }
  271. public function dropWhile($callable)
  272. {
  273. for ($i=0,$c=count($this->elements); $i<$c; $i++) {
  274. if (true !== call_user_func($callable, $this->elements[$i])) {
  275. break;
  276. }
  277. }
  278. return $this->createNew(array_slice($this->elements, $i));
  279. }
  280. public function exists($callable)
  281. {
  282. foreach ($this as $elem) {
  283. if ($callable($elem) === true) {
  284. return true;
  285. }
  286. }
  287. return false;
  288. }
  289. public function count()
  290. {
  291. return count($this->elements);
  292. }
  293. public function getIterator()
  294. {
  295. return new \ArrayIterator($this->elements);
  296. }
  297. protected function createNew(array $elements)
  298. {
  299. return new static($elements);
  300. }
  301. }