You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Collection.php 49KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076
  1. <?php
  2. namespace Illuminate\Support;
  3. use stdClass;
  4. use Countable;
  5. use Exception;
  6. use ArrayAccess;
  7. use Traversable;
  8. use ArrayIterator;
  9. use CachingIterator;
  10. use JsonSerializable;
  11. use IteratorAggregate;
  12. use Illuminate\Support\Traits\Macroable;
  13. use Illuminate\Contracts\Support\Jsonable;
  14. use Symfony\Component\VarDumper\VarDumper;
  15. use Illuminate\Contracts\Support\Arrayable;
  16. /**
  17. * @property-read HigherOrderCollectionProxy $average
  18. * @property-read HigherOrderCollectionProxy $avg
  19. * @property-read HigherOrderCollectionProxy $contains
  20. * @property-read HigherOrderCollectionProxy $each
  21. * @property-read HigherOrderCollectionProxy $every
  22. * @property-read HigherOrderCollectionProxy $filter
  23. * @property-read HigherOrderCollectionProxy $first
  24. * @property-read HigherOrderCollectionProxy $flatMap
  25. * @property-read HigherOrderCollectionProxy $groupBy
  26. * @property-read HigherOrderCollectionProxy $keyBy
  27. * @property-read HigherOrderCollectionProxy $map
  28. * @property-read HigherOrderCollectionProxy $max
  29. * @property-read HigherOrderCollectionProxy $min
  30. * @property-read HigherOrderCollectionProxy $partition
  31. * @property-read HigherOrderCollectionProxy $reject
  32. * @property-read HigherOrderCollectionProxy $sortBy
  33. * @property-read HigherOrderCollectionProxy $sortByDesc
  34. * @property-read HigherOrderCollectionProxy $sum
  35. * @property-read HigherOrderCollectionProxy $unique
  36. *
  37. * Class Collection
  38. */
  39. class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
  40. {
  41. use Macroable;
  42. /**
  43. * The items contained in the collection.
  44. *
  45. * @var array
  46. */
  47. protected $items = [];
  48. /**
  49. * The methods that can be proxied.
  50. *
  51. * @var array
  52. */
  53. protected static $proxies = [
  54. 'average', 'avg', 'contains', 'each', 'every', 'filter', 'first',
  55. 'flatMap', 'groupBy', 'keyBy', 'map', 'max', 'min', 'partition',
  56. 'reject', 'some', 'sortBy', 'sortByDesc', 'sum', 'unique',
  57. ];
  58. /**
  59. * Create a new collection.
  60. *
  61. * @param mixed $items
  62. * @return void
  63. */
  64. public function __construct($items = [])
  65. {
  66. $this->items = $this->getArrayableItems($items);
  67. }
  68. /**
  69. * Create a new collection instance if the value isn't one already.
  70. *
  71. * @param mixed $items
  72. * @return static
  73. */
  74. public static function make($items = [])
  75. {
  76. return new static($items);
  77. }
  78. /**
  79. * Wrap the given value in a collection if applicable.
  80. *
  81. * @param mixed $value
  82. * @return static
  83. */
  84. public static function wrap($value)
  85. {
  86. return $value instanceof self
  87. ? new static($value)
  88. : new static(Arr::wrap($value));
  89. }
  90. /**
  91. * Get the underlying items from the given collection if applicable.
  92. *
  93. * @param array|static $value
  94. * @return array
  95. */
  96. public static function unwrap($value)
  97. {
  98. return $value instanceof self ? $value->all() : $value;
  99. }
  100. /**
  101. * Create a new collection by invoking the callback a given amount of times.
  102. *
  103. * @param int $number
  104. * @param callable $callback
  105. * @return static
  106. */
  107. public static function times($number, callable $callback = null)
  108. {
  109. if ($number < 1) {
  110. return new static;
  111. }
  112. if (is_null($callback)) {
  113. return new static(range(1, $number));
  114. }
  115. return (new static(range(1, $number)))->map($callback);
  116. }
  117. /**
  118. * Get all of the items in the collection.
  119. *
  120. * @return array
  121. */
  122. public function all()
  123. {
  124. return $this->items;
  125. }
  126. /**
  127. * Get the average value of a given key.
  128. *
  129. * @param callable|string|null $callback
  130. * @return mixed
  131. */
  132. public function avg($callback = null)
  133. {
  134. $callback = $this->valueRetriever($callback);
  135. $items = $this->map(function ($value) use ($callback) {
  136. return $callback($value);
  137. })->filter(function ($value) {
  138. return ! is_null($value);
  139. });
  140. if ($count = $items->count()) {
  141. return $items->sum() / $count;
  142. }
  143. }
  144. /**
  145. * Alias for the "avg" method.
  146. *
  147. * @param callable|string|null $callback
  148. * @return mixed
  149. */
  150. public function average($callback = null)
  151. {
  152. return $this->avg($callback);
  153. }
  154. /**
  155. * Get the median of a given key.
  156. *
  157. * @param string|array|null $key
  158. * @return mixed
  159. */
  160. public function median($key = null)
  161. {
  162. $values = (isset($key) ? $this->pluck($key) : $this)
  163. ->filter(function ($item) {
  164. return ! is_null($item);
  165. })->sort()->values();
  166. $count = $values->count();
  167. if ($count === 0) {
  168. return;
  169. }
  170. $middle = (int) ($count / 2);
  171. if ($count % 2) {
  172. return $values->get($middle);
  173. }
  174. return (new static([
  175. $values->get($middle - 1), $values->get($middle),
  176. ]))->average();
  177. }
  178. /**
  179. * Get the mode of a given key.
  180. *
  181. * @param string|array|null $key
  182. * @return array|null
  183. */
  184. public function mode($key = null)
  185. {
  186. if ($this->count() === 0) {
  187. return;
  188. }
  189. $collection = isset($key) ? $this->pluck($key) : $this;
  190. $counts = new self;
  191. $collection->each(function ($value) use ($counts) {
  192. $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
  193. });
  194. $sorted = $counts->sort();
  195. $highestValue = $sorted->last();
  196. return $sorted->filter(function ($value) use ($highestValue) {
  197. return $value == $highestValue;
  198. })->sort()->keys()->all();
  199. }
  200. /**
  201. * Collapse the collection of items into a single array.
  202. *
  203. * @return static
  204. */
  205. public function collapse()
  206. {
  207. return new static(Arr::collapse($this->items));
  208. }
  209. /**
  210. * Alias for the "contains" method.
  211. *
  212. * @param mixed $key
  213. * @param mixed $operator
  214. * @param mixed $value
  215. * @return bool
  216. */
  217. public function some($key, $operator = null, $value = null)
  218. {
  219. return $this->contains(...func_get_args());
  220. }
  221. /**
  222. * Determine if an item exists in the collection.
  223. *
  224. * @param mixed $key
  225. * @param mixed $operator
  226. * @param mixed $value
  227. * @return bool
  228. */
  229. public function contains($key, $operator = null, $value = null)
  230. {
  231. if (func_num_args() === 1) {
  232. if ($this->useAsCallable($key)) {
  233. $placeholder = new stdClass;
  234. return $this->first($key, $placeholder) !== $placeholder;
  235. }
  236. return in_array($key, $this->items);
  237. }
  238. return $this->contains($this->operatorForWhere(...func_get_args()));
  239. }
  240. /**
  241. * Determine if an item exists in the collection using strict comparison.
  242. *
  243. * @param mixed $key
  244. * @param mixed $value
  245. * @return bool
  246. */
  247. public function containsStrict($key, $value = null)
  248. {
  249. if (func_num_args() === 2) {
  250. return $this->contains(function ($item) use ($key, $value) {
  251. return data_get($item, $key) === $value;
  252. });
  253. }
  254. if ($this->useAsCallable($key)) {
  255. return ! is_null($this->first($key));
  256. }
  257. return in_array($key, $this->items, true);
  258. }
  259. /**
  260. * Cross join with the given lists, returning all possible permutations.
  261. *
  262. * @param mixed ...$lists
  263. * @return static
  264. */
  265. public function crossJoin(...$lists)
  266. {
  267. return new static(Arr::crossJoin(
  268. $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
  269. ));
  270. }
  271. /**
  272. * Dump the collection and end the script.
  273. *
  274. * @param mixed ...$args
  275. * @return void
  276. */
  277. public function dd(...$args)
  278. {
  279. call_user_func_array([$this, 'dump'], $args);
  280. die(1);
  281. }
  282. /**
  283. * Dump the collection.
  284. *
  285. * @return $this
  286. */
  287. public function dump()
  288. {
  289. (new static(func_get_args()))
  290. ->push($this)
  291. ->each(function ($item) {
  292. VarDumper::dump($item);
  293. });
  294. return $this;
  295. }
  296. /**
  297. * Get the items in the collection that are not present in the given items.
  298. *
  299. * @param mixed $items
  300. * @return static
  301. */
  302. public function diff($items)
  303. {
  304. return new static(array_diff($this->items, $this->getArrayableItems($items)));
  305. }
  306. /**
  307. * Get the items in the collection that are not present in the given items.
  308. *
  309. * @param mixed $items
  310. * @param callable $callback
  311. * @return static
  312. */
  313. public function diffUsing($items, callable $callback)
  314. {
  315. return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
  316. }
  317. /**
  318. * Get the items in the collection whose keys and values are not present in the given items.
  319. *
  320. * @param mixed $items
  321. * @return static
  322. */
  323. public function diffAssoc($items)
  324. {
  325. return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
  326. }
  327. /**
  328. * Get the items in the collection whose keys and values are not present in the given items.
  329. *
  330. * @param mixed $items
  331. * @param callable $callback
  332. * @return static
  333. */
  334. public function diffAssocUsing($items, callable $callback)
  335. {
  336. return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));
  337. }
  338. /**
  339. * Get the items in the collection whose keys are not present in the given items.
  340. *
  341. * @param mixed $items
  342. * @return static
  343. */
  344. public function diffKeys($items)
  345. {
  346. return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
  347. }
  348. /**
  349. * Get the items in the collection whose keys are not present in the given items.
  350. *
  351. * @param mixed $items
  352. * @param callable $callback
  353. * @return static
  354. */
  355. public function diffKeysUsing($items, callable $callback)
  356. {
  357. return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
  358. }
  359. /**
  360. * Execute a callback over each item.
  361. *
  362. * @param callable $callback
  363. * @return $this
  364. */
  365. public function each(callable $callback)
  366. {
  367. foreach ($this->items as $key => $item) {
  368. if ($callback($item, $key) === false) {
  369. break;
  370. }
  371. }
  372. return $this;
  373. }
  374. /**
  375. * Execute a callback over each nested chunk of items.
  376. *
  377. * @param callable $callback
  378. * @return static
  379. */
  380. public function eachSpread(callable $callback)
  381. {
  382. return $this->each(function ($chunk, $key) use ($callback) {
  383. $chunk[] = $key;
  384. return $callback(...$chunk);
  385. });
  386. }
  387. /**
  388. * Determine if all items in the collection pass the given test.
  389. *
  390. * @param string|callable $key
  391. * @param mixed $operator
  392. * @param mixed $value
  393. * @return bool
  394. */
  395. public function every($key, $operator = null, $value = null)
  396. {
  397. if (func_num_args() === 1) {
  398. $callback = $this->valueRetriever($key);
  399. foreach ($this->items as $k => $v) {
  400. if (! $callback($v, $k)) {
  401. return false;
  402. }
  403. }
  404. return true;
  405. }
  406. return $this->every($this->operatorForWhere(...func_get_args()));
  407. }
  408. /**
  409. * Get all items except for those with the specified keys.
  410. *
  411. * @param \Illuminate\Support\Collection|mixed $keys
  412. * @return static
  413. */
  414. public function except($keys)
  415. {
  416. if ($keys instanceof self) {
  417. $keys = $keys->all();
  418. } elseif (! is_array($keys)) {
  419. $keys = func_get_args();
  420. }
  421. return new static(Arr::except($this->items, $keys));
  422. }
  423. /**
  424. * Run a filter over each of the items.
  425. *
  426. * @param callable|null $callback
  427. * @return static
  428. */
  429. public function filter(callable $callback = null)
  430. {
  431. if ($callback) {
  432. return new static(Arr::where($this->items, $callback));
  433. }
  434. return new static(array_filter($this->items));
  435. }
  436. /**
  437. * Apply the callback if the value is truthy.
  438. *
  439. * @param bool $value
  440. * @param callable $callback
  441. * @param callable $default
  442. * @return static|mixed
  443. */
  444. public function when($value, callable $callback, callable $default = null)
  445. {
  446. if ($value) {
  447. return $callback($this, $value);
  448. } elseif ($default) {
  449. return $default($this, $value);
  450. }
  451. return $this;
  452. }
  453. /**
  454. * Apply the callback if the collection is empty.
  455. *
  456. * @param callable $callback
  457. * @param callable $default
  458. * @return static|mixed
  459. */
  460. public function whenEmpty(callable $callback, callable $default = null)
  461. {
  462. return $this->when($this->isEmpty(), $callback, $default);
  463. }
  464. /**
  465. * Apply the callback if the collection is not empty.
  466. *
  467. * @param callable $callback
  468. * @param callable $default
  469. * @return static|mixed
  470. */
  471. public function whenNotEmpty(callable $callback, callable $default = null)
  472. {
  473. return $this->when($this->isNotEmpty(), $callback, $default);
  474. }
  475. /**
  476. * Apply the callback if the value is falsy.
  477. *
  478. * @param bool $value
  479. * @param callable $callback
  480. * @param callable $default
  481. * @return static|mixed
  482. */
  483. public function unless($value, callable $callback, callable $default = null)
  484. {
  485. return $this->when(! $value, $callback, $default);
  486. }
  487. /**
  488. * Apply the callback unless the collection is empty.
  489. *
  490. * @param callable $callback
  491. * @param callable $default
  492. * @return static|mixed
  493. */
  494. public function unlessEmpty(callable $callback, callable $default = null)
  495. {
  496. return $this->whenNotEmpty($callback, $default);
  497. }
  498. /**
  499. * Apply the callback unless the collection is not empty.
  500. *
  501. * @param callable $callback
  502. * @param callable $default
  503. * @return static|mixed
  504. */
  505. public function unlessNotEmpty(callable $callback, callable $default = null)
  506. {
  507. return $this->whenEmpty($callback, $default);
  508. }
  509. /**
  510. * Filter items by the given key value pair.
  511. *
  512. * @param string $key
  513. * @param mixed $operator
  514. * @param mixed $value
  515. * @return static
  516. */
  517. public function where($key, $operator = null, $value = null)
  518. {
  519. return $this->filter($this->operatorForWhere(...func_get_args()));
  520. }
  521. /**
  522. * Get an operator checker callback.
  523. *
  524. * @param string $key
  525. * @param string $operator
  526. * @param mixed $value
  527. * @return \Closure
  528. */
  529. protected function operatorForWhere($key, $operator = null, $value = null)
  530. {
  531. if (func_num_args() === 1) {
  532. $value = true;
  533. $operator = '=';
  534. }
  535. if (func_num_args() === 2) {
  536. $value = $operator;
  537. $operator = '=';
  538. }
  539. return function ($item) use ($key, $operator, $value) {
  540. $retrieved = data_get($item, $key);
  541. $strings = array_filter([$retrieved, $value], function ($value) {
  542. return is_string($value) || (is_object($value) && method_exists($value, '__toString'));
  543. });
  544. if (count($strings) < 2 && count(array_filter([$retrieved, $value], 'is_object')) == 1) {
  545. return in_array($operator, ['!=', '<>', '!==']);
  546. }
  547. switch ($operator) {
  548. default:
  549. case '=':
  550. case '==': return $retrieved == $value;
  551. case '!=':
  552. case '<>': return $retrieved != $value;
  553. case '<': return $retrieved < $value;
  554. case '>': return $retrieved > $value;
  555. case '<=': return $retrieved <= $value;
  556. case '>=': return $retrieved >= $value;
  557. case '===': return $retrieved === $value;
  558. case '!==': return $retrieved !== $value;
  559. }
  560. };
  561. }
  562. /**
  563. * Filter items by the given key value pair using strict comparison.
  564. *
  565. * @param string $key
  566. * @param mixed $value
  567. * @return static
  568. */
  569. public function whereStrict($key, $value)
  570. {
  571. return $this->where($key, '===', $value);
  572. }
  573. /**
  574. * Filter items by the given key value pair.
  575. *
  576. * @param string $key
  577. * @param mixed $values
  578. * @param bool $strict
  579. * @return static
  580. */
  581. public function whereIn($key, $values, $strict = false)
  582. {
  583. $values = $this->getArrayableItems($values);
  584. return $this->filter(function ($item) use ($key, $values, $strict) {
  585. return in_array(data_get($item, $key), $values, $strict);
  586. });
  587. }
  588. /**
  589. * Filter items by the given key value pair using strict comparison.
  590. *
  591. * @param string $key
  592. * @param mixed $values
  593. * @return static
  594. */
  595. public function whereInStrict($key, $values)
  596. {
  597. return $this->whereIn($key, $values, true);
  598. }
  599. /**
  600. * Filter items such that the value of the given key is between the given values.
  601. *
  602. * @param string $key
  603. * @param array $values
  604. * @return static
  605. */
  606. public function whereBetween($key, $values)
  607. {
  608. return $this->where($key, '>=', reset($values))->where($key, '<=', end($values));
  609. }
  610. /**
  611. * Filter items such that the value of the given key is not between the given values.
  612. *
  613. * @param string $key
  614. * @param array $values
  615. * @return static
  616. */
  617. public function whereNotBetween($key, $values)
  618. {
  619. return $this->filter(function ($item) use ($key, $values) {
  620. return data_get($item, $key) < reset($values) || data_get($item, $key) > end($values);
  621. });
  622. }
  623. /**
  624. * Filter items by the given key value pair.
  625. *
  626. * @param string $key
  627. * @param mixed $values
  628. * @param bool $strict
  629. * @return static
  630. */
  631. public function whereNotIn($key, $values, $strict = false)
  632. {
  633. $values = $this->getArrayableItems($values);
  634. return $this->reject(function ($item) use ($key, $values, $strict) {
  635. return in_array(data_get($item, $key), $values, $strict);
  636. });
  637. }
  638. /**
  639. * Filter items by the given key value pair using strict comparison.
  640. *
  641. * @param string $key
  642. * @param mixed $values
  643. * @return static
  644. */
  645. public function whereNotInStrict($key, $values)
  646. {
  647. return $this->whereNotIn($key, $values, true);
  648. }
  649. /**
  650. * Filter the items, removing any items that don't match the given type.
  651. *
  652. * @param string $type
  653. * @return static
  654. */
  655. public function whereInstanceOf($type)
  656. {
  657. return $this->filter(function ($value) use ($type) {
  658. return $value instanceof $type;
  659. });
  660. }
  661. /**
  662. * Get the first item from the collection.
  663. *
  664. * @param callable|null $callback
  665. * @param mixed $default
  666. * @return mixed
  667. */
  668. public function first(callable $callback = null, $default = null)
  669. {
  670. return Arr::first($this->items, $callback, $default);
  671. }
  672. /**
  673. * Get the first item by the given key value pair.
  674. *
  675. * @param string $key
  676. * @param mixed $operator
  677. * @param mixed $value
  678. * @return mixed
  679. */
  680. public function firstWhere($key, $operator = null, $value = null)
  681. {
  682. return $this->first($this->operatorForWhere(...func_get_args()));
  683. }
  684. /**
  685. * Get a flattened array of the items in the collection.
  686. *
  687. * @param int $depth
  688. * @return static
  689. */
  690. public function flatten($depth = INF)
  691. {
  692. return new static(Arr::flatten($this->items, $depth));
  693. }
  694. /**
  695. * Flip the items in the collection.
  696. *
  697. * @return static
  698. */
  699. public function flip()
  700. {
  701. return new static(array_flip($this->items));
  702. }
  703. /**
  704. * Remove an item from the collection by key.
  705. *
  706. * @param string|array $keys
  707. * @return $this
  708. */
  709. public function forget($keys)
  710. {
  711. foreach ((array) $keys as $key) {
  712. $this->offsetUnset($key);
  713. }
  714. return $this;
  715. }
  716. /**
  717. * Get an item from the collection by key.
  718. *
  719. * @param mixed $key
  720. * @param mixed $default
  721. * @return mixed
  722. */
  723. public function get($key, $default = null)
  724. {
  725. if ($this->offsetExists($key)) {
  726. return $this->items[$key];
  727. }
  728. return value($default);
  729. }
  730. /**
  731. * Group an associative array by a field or using a callback.
  732. *
  733. * @param array|callable|string $groupBy
  734. * @param bool $preserveKeys
  735. * @return static
  736. */
  737. public function groupBy($groupBy, $preserveKeys = false)
  738. {
  739. if (is_array($groupBy)) {
  740. $nextGroups = $groupBy;
  741. $groupBy = array_shift($nextGroups);
  742. }
  743. $groupBy = $this->valueRetriever($groupBy);
  744. $results = [];
  745. foreach ($this->items as $key => $value) {
  746. $groupKeys = $groupBy($value, $key);
  747. if (! is_array($groupKeys)) {
  748. $groupKeys = [$groupKeys];
  749. }
  750. foreach ($groupKeys as $groupKey) {
  751. $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
  752. if (! array_key_exists($groupKey, $results)) {
  753. $results[$groupKey] = new static;
  754. }
  755. $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
  756. }
  757. }
  758. $result = new static($results);
  759. if (! empty($nextGroups)) {
  760. return $result->map->groupBy($nextGroups, $preserveKeys);
  761. }
  762. return $result;
  763. }
  764. /**
  765. * Key an associative array by a field or using a callback.
  766. *
  767. * @param callable|string $keyBy
  768. * @return static
  769. */
  770. public function keyBy($keyBy)
  771. {
  772. $keyBy = $this->valueRetriever($keyBy);
  773. $results = [];
  774. foreach ($this->items as $key => $item) {
  775. $resolvedKey = $keyBy($item, $key);
  776. if (is_object($resolvedKey)) {
  777. $resolvedKey = (string) $resolvedKey;
  778. }
  779. $results[$resolvedKey] = $item;
  780. }
  781. return new static($results);
  782. }
  783. /**
  784. * Determine if an item exists in the collection by key.
  785. *
  786. * @param mixed $key
  787. * @return bool
  788. */
  789. public function has($key)
  790. {
  791. $keys = is_array($key) ? $key : func_get_args();
  792. foreach ($keys as $value) {
  793. if (! $this->offsetExists($value)) {
  794. return false;
  795. }
  796. }
  797. return true;
  798. }
  799. /**
  800. * Concatenate values of a given key as a string.
  801. *
  802. * @param string $value
  803. * @param string $glue
  804. * @return string
  805. */
  806. public function implode($value, $glue = null)
  807. {
  808. $first = $this->first();
  809. if (is_array($first) || is_object($first)) {
  810. return implode($glue, $this->pluck($value)->all());
  811. }
  812. return implode($value, $this->items);
  813. }
  814. /**
  815. * Intersect the collection with the given items.
  816. *
  817. * @param mixed $items
  818. * @return static
  819. */
  820. public function intersect($items)
  821. {
  822. return new static(array_intersect($this->items, $this->getArrayableItems($items)));
  823. }
  824. /**
  825. * Intersect the collection with the given items by key.
  826. *
  827. * @param mixed $items
  828. * @return static
  829. */
  830. public function intersectByKeys($items)
  831. {
  832. return new static(array_intersect_key(
  833. $this->items, $this->getArrayableItems($items)
  834. ));
  835. }
  836. /**
  837. * Determine if the collection is empty or not.
  838. *
  839. * @return bool
  840. */
  841. public function isEmpty()
  842. {
  843. return empty($this->items);
  844. }
  845. /**
  846. * Determine if the collection is not empty.
  847. *
  848. * @return bool
  849. */
  850. public function isNotEmpty()
  851. {
  852. return ! $this->isEmpty();
  853. }
  854. /**
  855. * Determine if the given value is callable, but not a string.
  856. *
  857. * @param mixed $value
  858. * @return bool
  859. */
  860. protected function useAsCallable($value)
  861. {
  862. return ! is_string($value) && is_callable($value);
  863. }
  864. /**
  865. * Join all items from the collection using a string. The final items can use a separate glue string.
  866. *
  867. * @param string $glue
  868. * @param string $finalGlue
  869. * @return string
  870. */
  871. public function join($glue, $finalGlue = '')
  872. {
  873. if ($finalGlue === '') {
  874. return $this->implode($glue);
  875. }
  876. $count = $this->count();
  877. if ($count === 0) {
  878. return '';
  879. }
  880. if ($count === 1) {
  881. return $this->last();
  882. }
  883. $collection = new static($this->items);
  884. $finalItem = $collection->pop();
  885. return $collection->implode($glue).$finalGlue.$finalItem;
  886. }
  887. /**
  888. * Get the keys of the collection items.
  889. *
  890. * @return static
  891. */
  892. public function keys()
  893. {
  894. return new static(array_keys($this->items));
  895. }
  896. /**
  897. * Get the last item from the collection.
  898. *
  899. * @param callable|null $callback
  900. * @param mixed $default
  901. * @return mixed
  902. */
  903. public function last(callable $callback = null, $default = null)
  904. {
  905. return Arr::last($this->items, $callback, $default);
  906. }
  907. /**
  908. * Get the values of a given key.
  909. *
  910. * @param string|array $value
  911. * @param string|null $key
  912. * @return static
  913. */
  914. public function pluck($value, $key = null)
  915. {
  916. return new static(Arr::pluck($this->items, $value, $key));
  917. }
  918. /**
  919. * Run a map over each of the items.
  920. *
  921. * @param callable $callback
  922. * @return static
  923. */
  924. public function map(callable $callback)
  925. {
  926. $keys = array_keys($this->items);
  927. $items = array_map($callback, $this->items, $keys);
  928. return new static(array_combine($keys, $items));
  929. }
  930. /**
  931. * Run a map over each nested chunk of items.
  932. *
  933. * @param callable $callback
  934. * @return static
  935. */
  936. public function mapSpread(callable $callback)
  937. {
  938. return $this->map(function ($chunk, $key) use ($callback) {
  939. $chunk[] = $key;
  940. return $callback(...$chunk);
  941. });
  942. }
  943. /**
  944. * Run a dictionary map over the items.
  945. *
  946. * The callback should return an associative array with a single key/value pair.
  947. *
  948. * @param callable $callback
  949. * @return static
  950. */
  951. public function mapToDictionary(callable $callback)
  952. {
  953. $dictionary = [];
  954. foreach ($this->items as $key => $item) {
  955. $pair = $callback($item, $key);
  956. $key = key($pair);
  957. $value = reset($pair);
  958. if (! isset($dictionary[$key])) {
  959. $dictionary[$key] = [];
  960. }
  961. $dictionary[$key][] = $value;
  962. }
  963. return new static($dictionary);
  964. }
  965. /**
  966. * Run a grouping map over the items.
  967. *
  968. * The callback should return an associative array with a single key/value pair.
  969. *
  970. * @param callable $callback
  971. * @return static
  972. */
  973. public function mapToGroups(callable $callback)
  974. {
  975. $groups = $this->mapToDictionary($callback);
  976. return $groups->map([$this, 'make']);
  977. }
  978. /**
  979. * Run an associative map over each of the items.
  980. *
  981. * The callback should return an associative array with a single key/value pair.
  982. *
  983. * @param callable $callback
  984. * @return static
  985. */
  986. public function mapWithKeys(callable $callback)
  987. {
  988. $result = [];
  989. foreach ($this->items as $key => $value) {
  990. $assoc = $callback($value, $key);
  991. foreach ($assoc as $mapKey => $mapValue) {
  992. $result[$mapKey] = $mapValue;
  993. }
  994. }
  995. return new static($result);
  996. }
  997. /**
  998. * Map a collection and flatten the result by a single level.
  999. *
  1000. * @param callable $callback
  1001. * @return static
  1002. */
  1003. public function flatMap(callable $callback)
  1004. {
  1005. return $this->map($callback)->collapse();
  1006. }
  1007. /**
  1008. * Map the values into a new class.
  1009. *
  1010. * @param string $class
  1011. * @return static
  1012. */
  1013. public function mapInto($class)
  1014. {
  1015. return $this->map(function ($value, $key) use ($class) {
  1016. return new $class($value, $key);
  1017. });
  1018. }
  1019. /**
  1020. * Get the max value of a given key.
  1021. *
  1022. * @param callable|string|null $callback
  1023. * @return mixed
  1024. */
  1025. public function max($callback = null)
  1026. {
  1027. $callback = $this->valueRetriever($callback);
  1028. return $this->filter(function ($value) {
  1029. return ! is_null($value);
  1030. })->reduce(function ($result, $item) use ($callback) {
  1031. $value = $callback($item);
  1032. return is_null($result) || $value > $result ? $value : $result;
  1033. });
  1034. }
  1035. /**
  1036. * Merge the collection with the given items.
  1037. *
  1038. * @param mixed $items
  1039. * @return static
  1040. */
  1041. public function merge($items)
  1042. {
  1043. return new static(array_merge($this->items, $this->getArrayableItems($items)));
  1044. }
  1045. /**
  1046. * Create a collection by using this collection for keys and another for its values.
  1047. *
  1048. * @param mixed $values
  1049. * @return static
  1050. */
  1051. public function combine($values)
  1052. {
  1053. return new static(array_combine($this->all(), $this->getArrayableItems($values)));
  1054. }
  1055. /**
  1056. * Union the collection with the given items.
  1057. *
  1058. * @param mixed $items
  1059. * @return static
  1060. */
  1061. public function union($items)
  1062. {
  1063. return new static($this->items + $this->getArrayableItems($items));
  1064. }
  1065. /**
  1066. * Get the min value of a given key.
  1067. *
  1068. * @param callable|string|null $callback
  1069. * @return mixed
  1070. */
  1071. public function min($callback = null)
  1072. {
  1073. $callback = $this->valueRetriever($callback);
  1074. return $this->map(function ($value) use ($callback) {
  1075. return $callback($value);
  1076. })->filter(function ($value) {
  1077. return ! is_null($value);
  1078. })->reduce(function ($result, $value) {
  1079. return is_null($result) || $value < $result ? $value : $result;
  1080. });
  1081. }
  1082. /**
  1083. * Create a new collection consisting of every n-th element.
  1084. *
  1085. * @param int $step
  1086. * @param int $offset
  1087. * @return static
  1088. */
  1089. public function nth($step, $offset = 0)
  1090. {
  1091. $new = [];
  1092. $position = 0;
  1093. foreach ($this->items as $item) {
  1094. if ($position % $step === $offset) {
  1095. $new[] = $item;
  1096. }
  1097. $position++;
  1098. }
  1099. return new static($new);
  1100. }
  1101. /**
  1102. * Get the items with the specified keys.
  1103. *
  1104. * @param mixed $keys
  1105. * @return static
  1106. */
  1107. public function only($keys)
  1108. {
  1109. if (is_null($keys)) {
  1110. return new static($this->items);
  1111. }
  1112. if ($keys instanceof self) {
  1113. $keys = $keys->all();
  1114. }
  1115. $keys = is_array($keys) ? $keys : func_get_args();
  1116. return new static(Arr::only($this->items, $keys));
  1117. }
  1118. /**
  1119. * "Paginate" the collection by slicing it into a smaller collection.
  1120. *
  1121. * @param int $page
  1122. * @param int $perPage
  1123. * @return static
  1124. */
  1125. public function forPage($page, $perPage)
  1126. {
  1127. $offset = max(0, ($page - 1) * $perPage);
  1128. return $this->slice($offset, $perPage);
  1129. }
  1130. /**
  1131. * Partition the collection into two arrays using the given callback or key.
  1132. *
  1133. * @param callable|string $key
  1134. * @param mixed $operator
  1135. * @param mixed $value
  1136. * @return static
  1137. */
  1138. public function partition($key, $operator = null, $value = null)
  1139. {
  1140. $partitions = [new static, new static];
  1141. $callback = func_num_args() === 1
  1142. ? $this->valueRetriever($key)
  1143. : $this->operatorForWhere(...func_get_args());
  1144. foreach ($this->items as $key => $item) {
  1145. $partitions[(int) ! $callback($item, $key)][$key] = $item;
  1146. }
  1147. return new static($partitions);
  1148. }
  1149. /**
  1150. * Pass the collection to the given callback and return the result.
  1151. *
  1152. * @param callable $callback
  1153. * @return mixed
  1154. */
  1155. public function pipe(callable $callback)
  1156. {
  1157. return $callback($this);
  1158. }
  1159. /**
  1160. * Get and remove the last item from the collection.
  1161. *
  1162. * @return mixed
  1163. */
  1164. public function pop()
  1165. {
  1166. return array_pop($this->items);
  1167. }
  1168. /**
  1169. * Push an item onto the beginning of the collection.
  1170. *
  1171. * @param mixed $value
  1172. * @param mixed $key
  1173. * @return $this
  1174. */
  1175. public function prepend($value, $key = null)
  1176. {
  1177. $this->items = Arr::prepend($this->items, $value, $key);
  1178. return $this;
  1179. }
  1180. /**
  1181. * Push an item onto the end of the collection.
  1182. *
  1183. * @param mixed $value
  1184. * @return $this
  1185. */
  1186. public function push($value)
  1187. {
  1188. $this->offsetSet(null, $value);
  1189. return $this;
  1190. }
  1191. /**
  1192. * Push all of the given items onto the collection.
  1193. *
  1194. * @param iterable $source
  1195. * @return static
  1196. */
  1197. public function concat($source)
  1198. {
  1199. $result = new static($this);
  1200. foreach ($source as $item) {
  1201. $result->push($item);
  1202. }
  1203. return $result;
  1204. }
  1205. /**
  1206. * Get and remove an item from the collection.
  1207. *
  1208. * @param mixed $key
  1209. * @param mixed $default
  1210. * @return mixed
  1211. */
  1212. public function pull($key, $default = null)
  1213. {
  1214. return Arr::pull($this->items, $key, $default);
  1215. }
  1216. /**
  1217. * Put an item in the collection by key.
  1218. *
  1219. * @param mixed $key
  1220. * @param mixed $value
  1221. * @return $this
  1222. */
  1223. public function put($key, $value)
  1224. {
  1225. $this->offsetSet($key, $value);
  1226. return $this;
  1227. }
  1228. /**
  1229. * Get one or a specified number of items randomly from the collection.
  1230. *
  1231. * @param int|null $number
  1232. * @return static|mixed
  1233. *
  1234. * @throws \InvalidArgumentException
  1235. */
  1236. public function random($number = null)
  1237. {
  1238. if (is_null($number)) {
  1239. return Arr::random($this->items);
  1240. }
  1241. return new static(Arr::random($this->items, $number));
  1242. }
  1243. /**
  1244. * Reduce the collection to a single value.
  1245. *
  1246. * @param callable $callback
  1247. * @param mixed $initial
  1248. * @return mixed
  1249. */
  1250. public function reduce(callable $callback, $initial = null)
  1251. {
  1252. return array_reduce($this->items, $callback, $initial);
  1253. }
  1254. /**
  1255. * Create a collection of all elements that do not pass a given truth test.
  1256. *
  1257. * @param callable|mixed $callback
  1258. * @return static
  1259. */
  1260. public function reject($callback = true)
  1261. {
  1262. $useAsCallable = $this->useAsCallable($callback);
  1263. return $this->filter(function ($value, $key) use ($callback, $useAsCallable) {
  1264. return $useAsCallable
  1265. ? ! $callback($value, $key)
  1266. : $value != $callback;
  1267. });
  1268. }
  1269. /**
  1270. * Reverse items order.
  1271. *
  1272. * @return static
  1273. */
  1274. public function reverse()
  1275. {
  1276. return new static(array_reverse($this->items, true));
  1277. }
  1278. /**
  1279. * Search the collection for a given value and return the corresponding key if successful.
  1280. *
  1281. * @param mixed $value
  1282. * @param bool $strict
  1283. * @return mixed
  1284. */
  1285. public function search($value, $strict = false)
  1286. {
  1287. if (! $this->useAsCallable($value)) {
  1288. return array_search($value, $this->items, $strict);
  1289. }
  1290. foreach ($this->items as $key => $item) {
  1291. if (call_user_func($value, $item, $key)) {
  1292. return $key;
  1293. }
  1294. }
  1295. return false;
  1296. }
  1297. /**
  1298. * Get and remove the first item from the collection.
  1299. *
  1300. * @return mixed
  1301. */
  1302. public function shift()
  1303. {
  1304. return array_shift($this->items);
  1305. }
  1306. /**
  1307. * Shuffle the items in the collection.
  1308. *
  1309. * @param int $seed
  1310. * @return static
  1311. */
  1312. public function shuffle($seed = null)
  1313. {
  1314. return new static(Arr::shuffle($this->items, $seed));
  1315. }
  1316. /**
  1317. * Slice the underlying collection array.
  1318. *
  1319. * @param int $offset
  1320. * @param int $length
  1321. * @return static
  1322. */
  1323. public function slice($offset, $length = null)
  1324. {
  1325. return new static(array_slice($this->items, $offset, $length, true));
  1326. }
  1327. /**
  1328. * Split a collection into a certain number of groups.
  1329. *
  1330. * @param int $numberOfGroups
  1331. * @return static
  1332. */
  1333. public function split($numberOfGroups)
  1334. {
  1335. if ($this->isEmpty()) {
  1336. return new static;
  1337. }
  1338. $groups = new static;
  1339. $groupSize = floor($this->count() / $numberOfGroups);
  1340. $remain = $this->count() % $numberOfGroups;
  1341. $start = 0;
  1342. for ($i = 0; $i < $numberOfGroups; $i++) {
  1343. $size = $groupSize;
  1344. if ($i < $remain) {
  1345. $size++;
  1346. }
  1347. if ($size) {
  1348. $groups->push(new static(array_slice($this->items, $start, $size)));
  1349. $start += $size;
  1350. }
  1351. }
  1352. return $groups;
  1353. }
  1354. /**
  1355. * Chunk the underlying collection array.
  1356. *
  1357. * @param int $size
  1358. * @return static
  1359. */
  1360. public function chunk($size)
  1361. {
  1362. if ($size <= 0) {
  1363. return new static;
  1364. }
  1365. $chunks = [];
  1366. foreach (array_chunk($this->items, $size, true) as $chunk) {
  1367. $chunks[] = new static($chunk);
  1368. }
  1369. return new static($chunks);
  1370. }
  1371. /**
  1372. * Sort through each item with a callback.
  1373. *
  1374. * @param callable|null $callback
  1375. * @return static
  1376. */
  1377. public function sort(callable $callback = null)
  1378. {
  1379. $items = $this->items;
  1380. $callback
  1381. ? uasort($items, $callback)
  1382. : asort($items);
  1383. return new static($items);
  1384. }
  1385. /**
  1386. * Sort the collection using the given callback.
  1387. *
  1388. * @param callable|string $callback
  1389. * @param int $options
  1390. * @param bool $descending
  1391. * @return static
  1392. */
  1393. public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
  1394. {
  1395. $results = [];
  1396. $callback = $this->valueRetriever($callback);
  1397. // First we will loop through the items and get the comparator from a callback
  1398. // function which we were given. Then, we will sort the returned values and
  1399. // and grab the corresponding values for the sorted keys from this array.
  1400. foreach ($this->items as $key => $value) {
  1401. $results[$key] = $callback($value, $key);
  1402. }
  1403. $descending ? arsort($results, $options)
  1404. : asort($results, $options);
  1405. // Once we have sorted all of the keys in the array, we will loop through them
  1406. // and grab the corresponding model so we can set the underlying items list
  1407. // to the sorted version. Then we'll just return the collection instance.
  1408. foreach (array_keys($results) as $key) {
  1409. $results[$key] = $this->items[$key];
  1410. }
  1411. return new static($results);
  1412. }
  1413. /**
  1414. * Sort the collection in descending order using the given callback.
  1415. *
  1416. * @param callable|string $callback
  1417. * @param int $options
  1418. * @return static
  1419. */
  1420. public function sortByDesc($callback, $options = SORT_REGULAR)
  1421. {
  1422. return $this->sortBy($callback, $options, true);
  1423. }
  1424. /**
  1425. * Sort the collection keys.
  1426. *
  1427. * @param int $options
  1428. * @param bool $descending
  1429. * @return static
  1430. */
  1431. public function sortKeys($options = SORT_REGULAR, $descending = false)
  1432. {
  1433. $items = $this->items;
  1434. $descending ? krsort($items, $options) : ksort($items, $options);
  1435. return new static($items);
  1436. }
  1437. /**
  1438. * Sort the collection keys in descending order.
  1439. *
  1440. * @param int $options
  1441. * @return static
  1442. */
  1443. public function sortKeysDesc($options = SORT_REGULAR)
  1444. {
  1445. return $this->sortKeys($options, true);
  1446. }
  1447. /**
  1448. * Splice a portion of the underlying collection array.
  1449. *
  1450. * @param int $offset
  1451. * @param int|null $length
  1452. * @param mixed $replacement
  1453. * @return static
  1454. */
  1455. public function splice($offset, $length = null, $replacement = [])
  1456. {
  1457. if (func_num_args() === 1) {
  1458. return new static(array_splice($this->items, $offset));
  1459. }
  1460. return new static(array_splice($this->items, $offset, $length, $replacement));
  1461. }
  1462. /**
  1463. * Get the sum of the given values.
  1464. *
  1465. * @param callable|string|null $callback
  1466. * @return mixed
  1467. */
  1468. public function sum($callback = null)
  1469. {
  1470. if (is_null($callback)) {
  1471. return array_sum($this->items);
  1472. }
  1473. $callback = $this->valueRetriever($callback);
  1474. return $this->reduce(function ($result, $item) use ($callback) {
  1475. return $result + $callback($item);
  1476. }, 0);
  1477. }
  1478. /**
  1479. * Take the first or last {$limit} items.
  1480. *
  1481. * @param int $limit
  1482. * @return static
  1483. */
  1484. public function take($limit)
  1485. {
  1486. if ($limit < 0) {
  1487. return $this->slice($limit, abs($limit));
  1488. }
  1489. return $this->slice(0, $limit);
  1490. }
  1491. /**
  1492. * Pass the collection to the given callback and then return it.
  1493. *
  1494. * @param callable $callback
  1495. * @return $this
  1496. */
  1497. public function tap(callable $callback)
  1498. {
  1499. $callback(new static($this->items));
  1500. return $this;
  1501. }
  1502. /**
  1503. * Transform each item in the collection using a callback.
  1504. *
  1505. * @param callable $callback
  1506. * @return $this
  1507. */
  1508. public function transform(callable $callback)
  1509. {
  1510. $this->items = $this->map($callback)->all();
  1511. return $this;
  1512. }
  1513. /**
  1514. * Return only unique items from the collection array.
  1515. *
  1516. * @param string|callable|null $key
  1517. * @param bool $strict
  1518. * @return static
  1519. */
  1520. public function unique($key = null, $strict = false)
  1521. {
  1522. $callback = $this->valueRetriever($key);
  1523. $exists = [];
  1524. return $this->reject(function ($item, $key) use ($callback, $strict, &$exists) {
  1525. if (in_array($id = $callback($item, $key), $exists, $strict)) {
  1526. return true;
  1527. }
  1528. $exists[] = $id;
  1529. });
  1530. }
  1531. /**
  1532. * Return only unique items from the collection array using strict comparison.
  1533. *
  1534. * @param string|callable|null $key
  1535. * @return static
  1536. */
  1537. public function uniqueStrict($key = null)
  1538. {
  1539. return $this->unique($key, true);
  1540. }
  1541. /**
  1542. * Reset the keys on the underlying array.
  1543. *
  1544. * @return static
  1545. */
  1546. public function values()
  1547. {
  1548. return new static(array_values($this->items));
  1549. }
  1550. /**
  1551. * Get a value retrieving callback.
  1552. *
  1553. * @param string $value
  1554. * @return callable
  1555. */
  1556. protected function valueRetriever($value)
  1557. {
  1558. if ($this->useAsCallable($value)) {
  1559. return $value;
  1560. }
  1561. return function ($item) use ($value) {
  1562. return data_get($item, $value);
  1563. };
  1564. }
  1565. /**
  1566. * Zip the collection together with one or more arrays.
  1567. *
  1568. * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
  1569. * => [[1, 4], [2, 5], [3, 6]]
  1570. *
  1571. * @param mixed ...$items
  1572. * @return static
  1573. */
  1574. public function zip($items)
  1575. {
  1576. $arrayableItems = array_map(function ($items) {
  1577. return $this->getArrayableItems($items);
  1578. }, func_get_args());
  1579. $params = array_merge([function () {
  1580. return new static(func_get_args());
  1581. }, $this->items], $arrayableItems);
  1582. return new static(call_user_func_array('array_map', $params));
  1583. }
  1584. /**
  1585. * Pad collection to the specified length with a value.
  1586. *
  1587. * @param int $size
  1588. * @param mixed $value
  1589. * @return static
  1590. */
  1591. public function pad($size, $value)
  1592. {
  1593. return new static(array_pad($this->items, $size, $value));
  1594. }
  1595. /**
  1596. * Get the collection of items as a plain array.
  1597. *
  1598. * @return array
  1599. */
  1600. public function toArray()
  1601. {
  1602. return array_map(function ($value) {
  1603. return $value instanceof Arrayable ? $value->toArray() : $value;
  1604. }, $this->items);
  1605. }
  1606. /**
  1607. * Convert the object into something JSON serializable.
  1608. *
  1609. * @return array
  1610. */
  1611. public function jsonSerialize()
  1612. {
  1613. return array_map(function ($value) {
  1614. if ($value instanceof JsonSerializable) {
  1615. return $value->jsonSerialize();
  1616. } elseif ($value instanceof Jsonable) {
  1617. return json_decode($value->toJson(), true);
  1618. } elseif ($value instanceof Arrayable) {
  1619. return $value->toArray();
  1620. }
  1621. return $value;
  1622. }, $this->items);
  1623. }
  1624. /**
  1625. * Get the collection of items as JSON.
  1626. *
  1627. * @param int $options
  1628. * @return string
  1629. */
  1630. public function toJson($options = 0)
  1631. {
  1632. return json_encode($this->jsonSerialize(), $options);
  1633. }
  1634. /**
  1635. * Get an iterator for the items.
  1636. *
  1637. * @return \ArrayIterator
  1638. */
  1639. public function getIterator()
  1640. {
  1641. return new ArrayIterator($this->items);
  1642. }
  1643. /**
  1644. * Get a CachingIterator instance.
  1645. *
  1646. * @param int $flags
  1647. * @return \CachingIterator
  1648. */
  1649. public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
  1650. {
  1651. return new CachingIterator($this->getIterator(), $flags);
  1652. }
  1653. /**
  1654. * Count the number of items in the collection.
  1655. *
  1656. * @return int
  1657. */
  1658. public function count()
  1659. {
  1660. return count($this->items);
  1661. }
  1662. /**
  1663. * Count the number of items in the collection using a given truth test.
  1664. *
  1665. * @param callable|null $callback
  1666. * @return static
  1667. */
  1668. public function countBy($callback = null)
  1669. {
  1670. if (is_null($callback)) {
  1671. $callback = function ($value) {
  1672. return $value;
  1673. };
  1674. }
  1675. return new static($this->groupBy($callback)->map(function ($value) {
  1676. return $value->count();
  1677. }));
  1678. }
  1679. /**
  1680. * Add an item to the collection.
  1681. *
  1682. * @param mixed $item
  1683. * @return $this
  1684. */
  1685. public function add($item)
  1686. {
  1687. $this->items[] = $item;
  1688. return $this;
  1689. }
  1690. /**
  1691. * Get a base Support collection instance from this collection.
  1692. *
  1693. * @return \Illuminate\Support\Collection
  1694. */
  1695. public function toBase()
  1696. {
  1697. return new self($this);
  1698. }
  1699. /**
  1700. * Determine if an item exists at an offset.
  1701. *
  1702. * @param mixed $key
  1703. * @return bool
  1704. */
  1705. public function offsetExists($key)
  1706. {
  1707. return array_key_exists($key, $this->items);
  1708. }
  1709. /**
  1710. * Get an item at a given offset.
  1711. *
  1712. * @param mixed $key
  1713. * @return mixed
  1714. */
  1715. public function offsetGet($key)
  1716. {
  1717. return $this->items[$key];
  1718. }
  1719. /**
  1720. * Set the item at a given offset.
  1721. *
  1722. * @param mixed $key
  1723. * @param mixed $value
  1724. * @return void
  1725. */
  1726. public function offsetSet($key, $value)
  1727. {
  1728. if (is_null($key)) {
  1729. $this->items[] = $value;
  1730. } else {
  1731. $this->items[$key] = $value;
  1732. }
  1733. }
  1734. /**
  1735. * Unset the item at a given offset.
  1736. *
  1737. * @param string $key
  1738. * @return void
  1739. */
  1740. public function offsetUnset($key)
  1741. {
  1742. unset($this->items[$key]);
  1743. }
  1744. /**
  1745. * Convert the collection to its string representation.
  1746. *
  1747. * @return string
  1748. */
  1749. public function __toString()
  1750. {
  1751. return $this->toJson();
  1752. }
  1753. /**
  1754. * Results array of items from Collection or Arrayable.
  1755. *
  1756. * @param mixed $items
  1757. * @return array
  1758. */
  1759. protected function getArrayableItems($items)
  1760. {
  1761. if (is_array($items)) {
  1762. return $items;
  1763. } elseif ($items instanceof self) {
  1764. return $items->all();
  1765. } elseif ($items instanceof Arrayable) {
  1766. return $items->toArray();
  1767. } elseif ($items instanceof Jsonable) {
  1768. return json_decode($items->toJson(), true);
  1769. } elseif ($items instanceof JsonSerializable) {
  1770. return $items->jsonSerialize();
  1771. } elseif ($items instanceof Traversable) {
  1772. return iterator_to_array($items);
  1773. }
  1774. return (array) $items;
  1775. }
  1776. /**
  1777. * Add a method to the list of proxied methods.
  1778. *
  1779. * @param string $method
  1780. * @return void
  1781. */
  1782. public static function proxy($method)
  1783. {
  1784. static::$proxies[] = $method;
  1785. }
  1786. /**
  1787. * Dynamically access collection proxies.
  1788. *
  1789. * @param string $key
  1790. * @return mixed
  1791. *
  1792. * @throws \Exception
  1793. */
  1794. public function __get($key)
  1795. {
  1796. if (! in_array($key, static::$proxies)) {
  1797. throw new Exception("Property [{$key}] does not exist on this collection instance.");
  1798. }
  1799. return new HigherOrderCollectionProxy($this, $key);
  1800. }
  1801. }