Completed
Push — master ( 693bba...08e4d5 )
by Antonio Carlos
06:10 queued 11s
created

Collection::duplicates()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
nc 3
nop 2
dl 0
loc 20
ccs 6
cts 6
cp 1
crap 4
rs 9.6
c 0
b 0
f 0
1
<?php
2
3
namespace IlluminateAgnostic\Arr\Support;
4
5
use ArrayAccess;
6
use ArrayIterator;
7
use IlluminateAgnostic\Arr\Support\Traits\EnumeratesValues;
8
use IlluminateAgnostic\Arr\Support\Traits\Macroable;
9
use stdClass;
10
11
class Collection implements ArrayAccess, Enumerable
12
{
13
    use EnumeratesValues, Macroable;
14
15
    /**
16
     * The items contained in the collection.
17
     *
18
     * @var array
19
     */
20
    protected $items = [];
21
22
    /**
23
     * Create a new collection.
24
     *
25
     * @param  mixed  $items
26
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
27
     */
28
    public function __construct($items = [])
29
    {
30
        $this->items = $this->getArrayableItems($items);
31
    }
32
33
    /**
34
     * Create a new collection by invoking the callback a given amount of times.
35
     *
36
     * @param  int  $number
37
     * @param  callable  $callback
38
     * @return static
39
     */
40
    public static function times($number, callable $callback = null)
41
    {
42
        if ($number < 1) {
43
            return new static;
44
        }
45
46
        if (is_null($callback)) {
47
            return new static(range(1, $number));
48
        }
49
50
        return (new static(range(1, $number)))->map($callback);
51
    }
52
53
    /**
54
     * Get all of the items in the collection.
55
     *
56
     * @return array
57
     */
58
    public function all()
59
    {
60
        return $this->items;
61
    }
62
63
    /**
64
     * Get a lazy collection for the items in this collection.
65
     *
66
     * @return \IlluminateAgnostic\Arr\Support\LazyCollection
67
     */
68
    public function lazy()
69
    {
70 238
        return new LazyCollection($this->items);
71
    }
72 238
73 238
    /**
74
     * Get the average value of a given key.
75
     *
76
     * @param  callable|string|null  $callback
77
     * @return mixed
78
     */
79
    public function avg($callback = null)
80
    {
81 10
        $callback = $this->valueRetriever($callback);
82
83 10
        $items = $this->map(function ($value) use ($callback) {
84
            return $callback($value);
85
        })->filter(function ($value) {
86
            return ! is_null($value);
87
        });
88
89
        if ($count = $items->count()) {
90
            return $items->sum() / $count;
91
        }
92 7
    }
93
94 7
    /**
95 2
     * Get the median of a given key.
96 7
     *
97
     * @param  string|array|null $key
98
     * @return mixed
99
     */
100
    public function median($key = null)
101
    {
102
        $values = (isset($key) ? $this->pluck($key) : $this)
103
            ->filter(function ($item) {
104
                return ! is_null($item);
105 3
            })->sort()->values();
106
107 3
        $count = $values->count();
108
109
        if ($count === 0) {
110
            return;
111
        }
112
113
        $middle = (int) ($count / 2);
114
115
        if ($count % 2) {
116
            return $values->get($middle);
117 1
        }
118
119 1
        return (new static([
120 1
            $values->get($middle - 1), $values->get($middle),
121
        ]))->average();
122
    }
123 1
124 1
    /**
125
     * Get the mode of a given key.
126
     *
127 1
     * @param  string|array|null  $key
128
     * @return array|null
129
     */
130
    public function mode($key = null)
131
    {
132
        if ($this->count() === 0) {
133
            return;
134
        }
135 116
136
        $collection = isset($key) ? $this->pluck($key) : $this;
137 116
138
        $counts = new self;
139
140
        $collection->each(function ($value) use ($counts) {
141
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
142
        });
143
144
        $sorted = $counts->sort();
145
146 4
        $highestValue = $sorted->last();
147
148 4
        return $sorted->filter(function ($value) use ($highestValue) {
149
            return $value == $highestValue;
150
        })->sort()->keys()->all();
151 4
    }
152
153 4
    /**
154 4
     * Collapse the collection of items into a single array.
155
     *
156 4
     * @return static
157 4
     */
158
    public function collapse()
159 1
    {
160
        return new static(Arr::collapse($this->items));
161
    }
162
163
    /**
164
     * Determine if an item exists in the collection.
165
     *
166
     * @param  mixed  $key
167 3
     * @param  mixed  $operator
168
     * @param  mixed  $value
169 3
     * @return bool
170
     */
171
    public function contains($key, $operator = null, $value = null)
172
    {
173
        if (func_num_args() === 1) {
174
            if ($this->useAsCallable($key)) {
175
                $placeholder = new stdClass;
176
177
                return $this->first($key, $placeholder) !== $placeholder;
178 6
            }
179
180 6
            return in_array($key, $this->items);
181
        }
182 5
183 6
        return $this->contains($this->operatorForWhere(...func_get_args()));
184
    }
185 6
186
    /**
187 6
     * Cross join with the given lists, returning all possible permutations.
188 1
     *
189
     * @param  mixed  ...$lists
190
     * @return static
191 5
     */
192
    public function crossJoin(...$lists)
193 5
    {
194 2
        return new static(Arr::crossJoin(
195
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
196
        ));
197 3
    }
198 3
199 3
    /**
200
     * Get the items in the collection that are not present in the given items.
201
     *
202
     * @param  mixed  $items
203
     * @return static
204
     */
205
    public function diff($items)
206
    {
207
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
208 4
    }
209
210 4
    /**
211 1
     * Get the items in the collection that are not present in the given items.
212
     *
213
     * @param  mixed  $items
214 3
     * @param  callable  $callback
215
     * @return static
216 3
     */
217
    public function diffUsing($items, callable $callback)
218
    {
219 3
        return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
220 3
    }
221
222 3
    /**
223
     * Get the items in the collection whose keys and values are not present in the given items.
224 3
     *
225
     * @param  mixed  $items
226
     * @return static
227 3
     */
228 3
    public function diffAssoc($items)
229
    {
230
        return new static(array_diff_assoc($this->items, $this->getArrayableItems($items)));
231
    }
232
233
    /**
234
     * Get the items in the collection whose keys and values are not present in the given items.
235
     *
236 3
     * @param  mixed  $items
237
     * @param  callable  $callback
238 3
     * @return static
239
     */
240
    public function diffAssocUsing($items, callable $callback)
241
    {
242
        return new static(array_diff_uassoc($this->items, $this->getArrayableItems($items), $callback));
243
    }
244
245
    /**
246
     * Get the items in the collection whose keys are not present in the given items.
247
     *
248
     * @param  mixed  $items
249 1
     * @return static
250
     */
251 1
    public function diffKeys($items)
252
    {
253
        return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
254
    }
255
256
    /**
257
     * Get the items in the collection whose keys are not present in the given items.
258
     *
259
     * @param  mixed   $items
260
     * @param  callable  $callback
261
     * @return static
262 4
     */
263
    public function diffKeysUsing($items, callable $callback)
264 4
    {
265 4
        return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
266 4
    }
267
268 4
    /**
269
     * Retrieve duplicate items from the collection.
270
     *
271 2
     * @param  callable|null  $callback
272
     * @param  bool  $strict
273
     * @return static
274 3
     */
275
    public function duplicates($callback = null, $strict = false)
276
    {
277
        $items = $this->map($this->valueRetriever($callback));
278
279
        $uniqueItems = $items->unique(null, $strict);
280
281
        $compare = $this->duplicateComparator($strict);
282
283
        $duplicates = new static;
284 1
285
        foreach ($items as $key => $value) {
286 1
            if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {
287
                $uniqueItems->shift();
288 1
            } else {
289 1
                $duplicates[$key] = $value;
290
            }
291
        }
292 1
293 1
        return $duplicates;
294
    }
295
296 1
    /**
297
     * Retrieve duplicate items from the collection using strict comparison.
298
     *
299
     * @param  callable|null  $callback
300
     * @return static
301
     */
302
    public function duplicatesStrict($callback = null)
303
    {
304
        return $this->duplicates($callback, true);
305 1
    }
306
307 1
    /**
308 1
     * Get the comparison function to detect duplicates.
309
     *
310
     * @param  bool  $strict
311
     * @return \Closure
312
     */
313
    protected function duplicateComparator($strict)
314
    {
315
        if ($strict) {
316
            return function ($a, $b) {
317
                return $a === $b;
318
            };
319
        }
320
321
        return function ($a, $b) {
322
            return $a == $b;
323
        };
324
    }
325
326
    /**
327
     * Get all items except for those with the specified keys.
328
     *
329
     * @param  \IlluminateAgnostic\Arr\Support\Collection|mixed  $keys
330
     * @return static
331
     */
332
    public function except($keys)
333
    {
334
        if ($keys instanceof Enumerable) {
335
            $keys = $keys->all();
336
        } elseif (! is_array($keys)) {
337
            $keys = func_get_args();
338
        }
339
340
        return new static(Arr::except($this->items, $keys));
341
    }
342
343
    /**
344
     * Run a filter over each of the items.
345
     *
346
     * @param  callable|null  $callback
347 3
     * @return static
348
     */
349 3
    public function filter(callable $callback = null)
350
    {
351
        if ($callback) {
352
            return new static(Arr::where($this->items, $callback));
353
        }
354
355
        return new static(array_filter($this->items));
356
    }
357
358
    /**
359 2
     * Get the first item from the collection passing the given truth test.
360
     *
361 2
     * @param  callable|null  $callback
362
     * @param  mixed  $default
363
     * @return mixed
364
     */
365
    public function first(callable $callback = null, $default = null)
366
    {
367
        return Arr::first($this->items, $callback, $default);
368
    }
369
370 2
    /**
371
     * Get a flattened array of the items in the collection.
372 2
     *
373
     * @param  int  $depth
374
     * @return static
375
     */
376
    public function flatten($depth = INF)
377
    {
378
        return new static(Arr::flatten($this->items, $depth));
379
    }
380
381
    /**
382 1
     * Flip the items in the collection.
383
     *
384 1
     * @return static
385
     */
386
    public function flip()
387
    {
388
        return new static(array_flip($this->items));
389
    }
390
391
    /**
392
     * Remove an item from the collection by key.
393 2
     *
394
     * @param  string|array  $keys
395 2
     * @return $this
396
     */
397
    public function forget($keys)
398
    {
399
        foreach ((array) $keys as $key) {
400
            $this->offsetUnset($key);
401
        }
402
403
        return $this;
404
    }
405 1
406
    /**
407 1
     * Get an item from the collection by key.
408
     *
409
     * @param  mixed  $key
410
     * @param  mixed  $default
411
     * @return mixed
412
     */
413
    public function get($key, $default = null)
414
    {
415
        if ($this->offsetExists($key)) {
416 7
            return $this->items[$key];
417
        }
418 7
419 7
        return value($default);
420 2
    }
421
422
    /**
423
     * Group an associative array by a field or using a callback.
424 7
     *
425
     * @param  array|callable|string  $groupBy
426
     * @param  bool  $preserveKeys
427
     * @return static
428
     */
429
    public function groupBy($groupBy, $preserveKeys = false)
430
    {
431
        if (is_array($groupBy)) {
432
            $nextGroups = $groupBy;
433 1
434
            $groupBy = array_shift($nextGroups);
435
        }
436 1
437
        $groupBy = $this->valueRetriever($groupBy);
438 1
439 1
        $results = [];
440
441
        foreach ($this->items as $key => $value) {
442
            $groupKeys = $groupBy($value, $key);
443
444
            if (! is_array($groupKeys)) {
445
                $groupKeys = [$groupKeys];
446
            }
447
448
            foreach ($groupKeys as $groupKey) {
449
                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
450 1
451
                if (! array_key_exists($groupKey, $results)) {
452 1
                    $results[$groupKey] = new static;
453 1
                }
454
455 1
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
456 1
            }
457 1
        }
458
459
        $result = new static($results);
460
461 1
        if (! empty($nextGroups)) {
462
            return $result->map->groupBy($nextGroups, $preserveKeys);
0 ignored issues
show
Documentation Bug introduced by
The method groupBy does not exist on object<IlluminateAgnosti...erOrderCollectionProxy>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
463
        }
464 1
465
        return $result;
466
    }
467
468
    /**
469
     * Key an associative array by a field or using a callback.
470
     *
471
     * @param  callable|string  $keyBy
472
     * @return static
473 2
     */
474
    public function keyBy($keyBy)
475 2
    {
476 2
        $keyBy = $this->valueRetriever($keyBy);
477 1
478 1
        $results = [];
479
480
        foreach ($this->items as $key => $item) {
481 2
            $resolvedKey = $keyBy($item, $key);
482
483
            if (is_object($resolvedKey)) {
484
                $resolvedKey = (string) $resolvedKey;
485
            }
486
487
            $results[$resolvedKey] = $item;
488
        }
489
490 32
        return new static($results);
491
    }
492 32
493 32
    /**
494
     * Determine if an item exists in the collection by key.
495
     *
496 1
     * @param  mixed  $key
497
     * @return bool
498
     */
499
    public function has($key)
500
    {
501
        $keys = is_array($key) ? $key : func_get_args();
502
503
        foreach ($keys as $value) {
504
            if (! $this->offsetExists($value)) {
505
                return false;
506
            }
507 12
        }
508
509 12
        return true;
510 8
    }
511 10
512 4
    /**
513
     * Concatenate values of a given key as a string.
514
     *
515 6
     * @param  string  $value
516
     * @param  string  $glue
517
     * @return string
518
     */
519
    public function implode($value, $glue = null)
520
    {
521
        $first = $this->first();
522
523
        if (is_array($first) || is_object($first)) {
524
            return implode($glue, $this->pluck($value)->all());
525 4
        }
526
527 4
        return implode($value, $this->items);
528
    }
529
530
    /**
531
     * Intersect the collection with the given items.
532
     *
533
     * @param  mixed  $items
534
     * @return static
535
     */
536
    public function intersect($items)
537 4
    {
538
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
539 4
    }
540
541
    /**
542
     * Intersect the collection with the given items by key.
543
     *
544
     * @param  mixed  $items
545
     * @return static
546
     */
547
    public function intersectByKeys($items)
548
    {
549
        return new static(array_intersect_key(
550 2
            $this->items, $this->getArrayableItems($items)
551
        ));
552 2
    }
553
554
    /**
555
     * Determine if the collection is empty or not.
556
     *
557
     * @return bool
558
     */
559
    public function isEmpty()
560
    {
561
        return empty($this->items);
562 2
    }
563
564 2
    /**
565
     * Join all items from the collection using a string. The final items can use a separate glue string.
566
     *
567
     * @param  string  $glue
568
     * @param  string  $finalGlue
569
     * @return string
570
     */
571
    public function join($glue, $finalGlue = '')
572
    {
573
        if ($finalGlue === '') {
574 2
            return $this->implode($glue);
575
        }
576 2
577
        $count = $this->count();
578
579
        if ($count === 0) {
580
            return '';
581
        }
582
583
        if ($count === 1) {
584
            return $this->last();
585
        }
586
587 3
        $collection = new static($this->items);
588
589 3
        $finalItem = $collection->pop();
590
591
        return $collection->implode($glue).$finalGlue.$finalItem;
592
    }
593
594
    /**
595
     * Get the keys of the collection items.
596
     *
597
     * @return static
598
     */
599
    public function keys()
600 9
    {
601
        return new static(array_keys($this->items));
602 9
    }
603 1
604
    /**
605 1
     * Get the last item from the collection.
606
     *
607
     * @param  callable|null  $callback
608 9
     * @param  mixed  $default
609 6
     * @return mixed
610
     */
611 6
    public function last(callable $callback = null, $default = null)
612
    {
613
        return Arr::last($this->items, $callback, $default);
614
    }
615 9
616
    /**
617
     * Get the values of a given key.
618 9
     *
619 9
     * @param  string|array  $value
620
     * @param  string|null  $key
621 9
     * @return static
622 1
     */
623
    public function pluck($value, $key = null)
624
    {
625 9
        return new static(Arr::pluck($this->items, $value, $key));
626
    }
627 9
628 9
    /**
629 6
     * Run a map over each of the items.
630 6
     *
631 6
     * @param  callable  $callback
632 6
     * @return static
633 6
     */
634 6
    public function map(callable $callback)
635 3
    {
636 1
        $keys = array_keys($this->items);
637
638 9
        $items = array_map($callback, $this->items, $keys);
639
640
        return new static(array_combine($keys, $items));
641
    }
642
643
    /**
644
     * Run a dictionary map over the items.
645
     *
646
     * The callback should return an associative array with a single key/value pair.
647
     *
648 1
     * @param  callable  $callback
649
     * @return static
650 1
     */
651
    public function mapToDictionary(callable $callback)
652
    {
653
        $dictionary = [];
654
655
        foreach ($this->items as $key => $item) {
656
            $pair = $callback($item, $key);
657
658
            $key = key($pair);
659
660
            $value = reset($pair);
661 2
662
            if (! isset($dictionary[$key])) {
663 2
                $dictionary[$key] = [];
664
            }
665
666 2
            $dictionary[$key][] = $value;
667 2
        }
668
669
        return new static($dictionary);
670
    }
671
672
    /**
673
     * Run an associative map over each of the items.
674
     *
675
     * The callback should return an associative array with a single key/value pair.
676
     *
677 1
     * @param  callable  $callback
678
     * @return static
679 1
     */
680
    public function mapWithKeys(callable $callback)
681
    {
682
        $result = [];
683
684
        foreach ($this->items as $key => $value) {
685
            $assoc = $callback($value, $key);
686
687
            foreach ($assoc as $mapKey => $mapValue) {
688
                $result[$mapKey] = $mapValue;
689 1
            }
690
        }
691 1
692
        return new static($result);
693
    }
694
695
    /**
696
     * Merge the collection with the given items.
697
     *
698
     * @param  mixed  $items
699
     * @return static
700
     */
701 1
    public function merge($items)
702
    {
703
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
704 1
    }
705 1
706
    /**
707
     * Recursively merge the collection with the given items.
708
     *
709
     * @param  mixed  $items
710
     * @return static
711
     */
712
    public function mergeRecursive($items)
713
    {
714
        return new static(array_merge_recursive($this->items, $this->getArrayableItems($items)));
715
    }
716 2
717
    /**
718 2
     * Create a collection by using this collection for keys and another for its values.
719
     *
720
     * @param  mixed  $values
721 2
     * @return static
722 2
     */
723
    public function combine($values)
724
    {
725
        return new static(array_combine($this->all(), $this->getArrayableItems($values)));
726
    }
727
728
    /**
729
     * Union the collection with the given items.
730
     *
731
     * @param  mixed  $items
732 1
     * @return static
733
     */
734 1
    public function union($items)
735
    {
736
        return new static($this->items + $this->getArrayableItems($items));
737
    }
738
739
    /**
740
     * Create a new collection consisting of every n-th element.
741
     *
742
     * @param  int  $step
743 1
     * @param  int  $offset
744
     * @return static
745
     */
746 1
    public function nth($step, $offset = 0)
747 1
    {
748
        $new = [];
749
750
        $position = 0;
751
752
        foreach ($this->items as $item) {
753
            if ($position % $step === $offset) {
754
                $new[] = $item;
755
            }
756
757 13
            $position++;
758
        }
759 13
760
        return new static($new);
761
    }
762
763
    /**
764
     * Get the items with the specified keys.
765
     *
766
     * @param  mixed  $keys
767
     * @return static
768
     */
769
    public function only($keys)
770 1
    {
771
        if (is_null($keys)) {
772 1
            return new static($this->items);
773
        }
774
775
        if ($keys instanceof Enumerable) {
776
            $keys = $keys->all();
777
        }
778
779
        $keys = is_array($keys) ? $keys : func_get_args();
780
781 3
        return new static(Arr::only($this->items, $keys));
782
    }
783 3
784
    /**
785
     * Get and remove the last item from the collection.
786
     *
787
     * @return mixed
788
     */
789
    public function pop()
790
    {
791 1
        return array_pop($this->items);
792
    }
793 1
794
    /**
795
     * Push an item onto the beginning of the collection.
796
     *
797
     * @param  mixed  $value
798
     * @param  mixed  $key
799
     * @return $this
800
     */
801
    public function prepend($value, $key = null)
802 2
    {
803
        $this->items = Arr::prepend($this->items, $value, $key);
804 2
805 2
        return $this;
806
    }
807
808 2
    /**
809
     * Push an item onto the end of the collection.
810
     *
811
     * @param  mixed  $value
812
     * @return $this
813
     */
814
    public function push($value)
815
    {
816
        $this->items[] = $value;
817
818 6
        return $this;
819
    }
820 6
821 5
    /**
822
     * Push all of the given items onto the collection.
823
     *
824 1
     * @param  iterable  $source
825
     * @return static
826
     */
827
    public function concat($source)
828
    {
829
        $result = new static($this);
830
831
        foreach ($source as $item) {
832
            $result->push($item);
833
        }
834 10
835
        return $result;
836 10
    }
837 1
838
    /**
839 1
     * Get and remove an item from the collection.
840
     *
841
     * @param  mixed  $key
842 10
     * @param  mixed  $default
843
     * @return mixed
844 10
     */
845
    public function pull($key, $default = null)
846 10
    {
847 10
        return Arr::pull($this->items, $key, $default);
848
    }
849 10
850 8
    /**
851
     * Put an item in the collection by key.
852
     *
853 10
     * @param  mixed  $key
854 10
     * @param  mixed  $value
855
     * @return $this
856 10
     */
857 10
    public function put($key, $value)
858
    {
859
        $this->offsetSet($key, $value);
860 10
861
        return $this;
862
    }
863
864 10
    /**
865
     * Get one or a specified number of items randomly from the collection.
866 10
     *
867 1
     * @param  int|null  $number
868
     * @return static|mixed
869
     *
870 10
     * @throws \InvalidArgumentException
871
     */
872
    public function random($number = null)
873
    {
874
        if (is_null($number)) {
875
            return Arr::random($this->items);
876
        }
877
878
        return new static(Arr::random($this->items, $number));
879 3
    }
880
881 3
    /**
882
     * Reduce the collection to a single value.
883 3
     *
884
     * @param  callable  $callback
885 3
     * @param  mixed  $initial
886 3
     * @return mixed
887
     */
888 3
    public function reduce(callable $callback, $initial = null)
889
    {
890
        return array_reduce($this->items, $callback, $initial);
891
    }
892 3
893
    /**
894
     * Replace the collection items with the given items.
895 3
     *
896
     * @param  mixed  $items
897
     * @return static
898
     */
899
    public function replace($items)
900
    {
901
        return new static(array_replace($this->items, $this->getArrayableItems($items)));
902
    }
903
904 2
    /**
905
     * Recursively replace the collection items with the given items.
906 2
     *
907
     * @param  mixed  $items
908 2
     * @return static
909 2
     */
910 2
    public function replaceRecursive($items)
911
    {
912
        return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
913
    }
914 2
915
    /**
916
     * Reverse items order.
917
     *
918
     * @return static
919
     */
920
    public function reverse()
921
    {
922
        return new static(array_reverse($this->items, true));
923
    }
924 2
925
    /**
926 2
     * Search the collection for a given value and return the corresponding key if successful.
927
     *
928 2
     * @param  mixed  $value
929 1
     * @param  bool  $strict
930
     * @return mixed
931
     */
932 2
    public function search($value, $strict = false)
933
    {
934
        if (! $this->useAsCallable($value)) {
935
            return array_search($value, $this->items, $strict);
936
        }
937
938
        foreach ($this->items as $key => $item) {
939
            if ($value($item, $key)) {
940
                return $key;
941 2
            }
942
        }
943 2
944
        return false;
945
    }
946
947
    /**
948
     * Get and remove the first item from the collection.
949
     *
950
     * @return mixed
951
     */
952 2
    public function shift()
953
    {
954 2
        return array_shift($this->items);
955 2
    }
956
957
    /**
958
     * Shuffle the items in the collection.
959
     *
960
     * @param  int  $seed
961
     * @return static
962
     */
963
    public function shuffle($seed = null)
964 19
    {
965
        return new static(Arr::shuffle($this->items, $seed));
966 19
    }
967
968
    /**
969
     * Skip the first {$count} items.
970
     *
971
     * @param  int  $count
972
     * @return static
973
     */
974 5
    public function skip($count)
975
    {
976 5
        return $this->slice($count);
977
    }
978
979
    /**
980
     * Slice the underlying collection array.
981
     *
982
     * @param  int  $offset
983
     * @param  int  $length
984
     * @return static
985 49
     */
986
    public function slice($offset, $length = null)
987 49
    {
988
        return new static(array_slice($this->items, $offset, $length, true));
989
    }
990
991
    /**
992
     * Split a collection into a certain number of groups.
993
     *
994
     * @param  int  $numberOfGroups
995
     * @return static
996
     */
997 1
    public function split($numberOfGroups)
998
    {
999 1
        if ($this->isEmpty()) {
1000 1
            return new static;
1001
        }
1002
1003 1
        $groups = new static;
1004
1005 1
        $groupSize = floor($this->count() / $numberOfGroups);
1006 1
1007
        $remain = $this->count() % $numberOfGroups;
1008
1009 1
        $start = 0;
1010 1
1011
        for ($i = 0; $i < $numberOfGroups; $i++) {
1012
            $size = $groupSize;
1013 1
1014
            if ($i < $remain) {
1015 1
                $size++;
1016
            }
1017 1
1018
            if ($size) {
1019
                $groups->push(new static(array_slice($this->items, $start, $size)));
1020
1021
                $start += $size;
1022
            }
1023
        }
1024
1025 6
        return $groups;
1026
    }
1027 6
1028
    /**
1029
     * Chunk the collection into chunks of the given size.
1030
     *
1031
     * @param  int  $size
1032
     * @return static
1033
     */
1034
    public function chunk($size)
1035
    {
1036
        if ($size <= 0) {
1037 8
            return new static;
1038
        }
1039 8
1040
        $chunks = [];
1041
1042
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1043
            $chunks[] = new static($chunk);
1044
        }
1045
1046
        return new static($chunks);
1047
    }
1048
1049 10
    /**
1050
     * Sort through each item with a callback.
1051 10
     *
1052
     * @param  callable|null  $callback
1053
     * @return static
1054
     */
1055
    public function sort(callable $callback = null)
1056
    {
1057
        $items = $this->items;
1058
1059
        $callback
1060 26
            ? uasort($items, $callback)
1061
            : asort($items);
1062 26
1063
        return new static($items);
1064 26
    }
1065
1066 26
    /**
1067
     * Sort the collection using the given callback.
1068
     *
1069
     * @param  callable|string  $callback
1070
     * @param  int  $options
1071
     * @param  bool  $descending
1072
     * @return static
1073
     */
1074
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1075 1
    {
1076
        $results = [];
1077
1078 1
        $callback = $this->valueRetriever($callback);
1079
1080 1
        // First we will loop through the items and get the comparator from a callback
1081 1
        // function which we were given. Then, we will sort the returned values and
1082
        // and grab the corresponding values for the sorted keys from this array.
1083
        foreach ($this->items as $key => $value) {
1084
            $results[$key] = $callback($value, $key);
1085
        }
1086
1087
        $descending ? arsort($results, $options)
1088
            : asort($results, $options);
1089
1090
        // Once we have sorted all of the keys in the array, we will loop through them
1091
        // and grab the corresponding model so we can set the underlying items list
1092 4
        // to the sorted version. Then we'll just return the collection instance.
1093
        foreach (array_keys($results) as $key) {
1094 4
            $results[$key] = $this->items[$key];
1095
        }
1096 4
1097 4
        return new static($results);
1098
    }
1099 4
1100
    /**
1101 4
     * Sort the collection in descending order using the given callback.
1102
     *
1103 4
     * @param  callable|string  $callback
1104 4
     * @param  int  $options
1105
     * @return static
1106
     */
1107 4
    public function sortByDesc($callback, $options = SORT_REGULAR)
1108
    {
1109
        return $this->sortBy($callback, $options, true);
1110 4
    }
1111
1112
    /**
1113
     * Sort the collection keys.
1114
     *
1115
     * @param  int  $options
1116
     * @param  bool  $descending
1117
     * @return static
1118
     */
1119
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1120
    {
1121 2
        $items = $this->items;
1122
1123 2
        $descending ? krsort($items, $options) : ksort($items, $options);
1124
1125 2
        return new static($items);
1126
    }
1127
1128
    /**
1129
     * Sort the collection keys in descending order.
1130
     *
1131
     * @param  int $options
1132
     * @return static
1133
     */
1134
    public function sortKeysDesc($options = SORT_REGULAR)
1135
    {
1136 5
        return $this->sortKeys($options, true);
1137
    }
1138 5
1139
    /**
1140 5
     * Splice a portion of the underlying collection array.
1141 5
     *
1142
     * @param  int  $offset
1143 5
     * @param  int|null  $length
1144 5
     * @param  mixed  $replacement
1145
     * @return static
1146
     */
1147
    public function splice($offset, $length = null, $replacement = [])
1148 5
    {
1149
        if (func_num_args() === 1) {
1150
            return new static(array_splice($this->items, $offset));
1151
        }
1152
1153
        return new static(array_splice($this->items, $offset, $length, $replacement));
1154
    }
1155
1156
    /**
1157 1
     * Take the first or last {$limit} items.
1158
     *
1159 1
     * @param  int  $limit
1160
     * @return static
1161
     */
1162
    public function take($limit)
1163
    {
1164
        if ($limit < 0) {
1165
            return $this->slice($limit, abs($limit));
1166
        }
1167
1168 1
        return $this->slice(0, $limit);
1169
    }
1170
1171 1
    /**
1172 1
     * Transform each item in the collection using a callback.
1173
     *
1174
     * @param  callable  $callback
1175
     * @return $this
1176
     */
1177
    public function transform(callable $callback)
1178
    {
1179
        $this->items = $this->map($callback)->all();
1180
1181 1
        return $this;
1182
    }
1183 1
1184
    /**
1185
     * Reset the keys on the underlying array.
1186 1
     *
1187
     * @return static
1188 1
     */
1189
    public function values()
1190 1
    {
1191 1
        return new static(array_values($this->items));
1192
    }
1193
1194
    /**
1195
     * Zip the collection together with one or more arrays.
1196
     *
1197
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1198
     *      => [[1, 4], [2, 5], [3, 6]]
1199
     *
1200 3
     * @param  mixed ...$items
1201
     * @return static
1202 3
     */
1203
    public function zip($items)
1204
    {
1205
        $arrayableItems = array_map(function ($items) {
1206
            return $this->getArrayableItems($items);
1207
        }, func_get_args());
1208
1209
        $params = array_merge([function () {
1210
            return new static(func_get_args());
1211 2
        }, $this->items], $arrayableItems);
1212
1213 2
        return new static(call_user_func_array('array_map', $params));
1214
    }
1215
1216
    /**
1217
     * Pad collection to the specified length with a value.
1218
     *
1219
     * @param  int  $size
1220
     * @param  mixed  $value
1221
     * @return static
1222 3
     */
1223
    public function pad($size, $value)
1224 3
    {
1225
        return new static(array_pad($this->items, $size, $value));
1226
    }
1227
1228
    /**
1229
     * Get an iterator for the items.
1230
     *
1231
     * @return \ArrayIterator
1232
     */
1233 1
    public function getIterator()
1234
    {
1235 1
        return new ArrayIterator($this->items);
1236
    }
1237
1238 1
    /**
1239
     * Count the number of items in the collection.
1240 1
     *
1241
     * @return int
1242 1
     */
1243 1
    public function count()
1244
    {
1245
        return count($this->items);
1246
    }
1247
1248
    /**
1249
     * Add an item to the collection.
1250
     *
1251
     * @param  mixed  $item
1252
     * @return $this
1253 1
     */
1254
    public function add($item)
1255 1
    {
1256
        $this->items[] = $item;
1257 1
1258
        return $this;
1259 1
    }
1260 1
1261 1
    /**
1262
     * Get a base Support collection instance from this collection.
1263
     *
1264 1
     * @return \IlluminateAgnostic\Arr\Support\Collection
1265
     */
1266
    public function toBase()
1267 1
    {
1268
        return new self($this);
1269
    }
1270
1271
    /**
1272
     * Determine if an item exists at an offset.
1273
     *
1274
     * @param  mixed  $key
1275
     * @return bool
1276 1
     */
1277
    public function offsetExists($key)
1278 1
    {
1279 1
        return array_key_exists($key, $this->items);
1280
    }
1281
1282 1
    /**
1283 1
     * Get an item at a given offset.
1284
     *
1285
     * @param  mixed  $key
1286 1
     * @return mixed
1287
     */
1288 1
    public function offsetGet($key)
1289
    {
1290
        return $this->items[$key];
1291
    }
1292
1293
    /**
1294
     * Set the item at a given offset.
1295
     *
1296
     * @param  mixed  $key
1297
     * @param  mixed  $value
1298 1
     * @return void
1299
     */
1300 1
    public function offsetSet($key, $value)
1301
    {
1302 1
        if (is_null($key)) {
1303
            $this->items[] = $value;
1304
        } else {
1305
            $this->items[$key] = $value;
1306
        }
1307
    }
1308
1309
    /**
1310
     * Unset the item at a given offset.
1311
     *
1312
     * @param  string  $key
1313 7
     * @return void
1314
     */
1315 7
    public function offsetUnset($key)
1316
    {
1317 7
        unset($this->items[$key]);
1318 6
    }
1319
}
1320