Completed
Push — master ( 08e4d5...a0c1d4 )
by Antonio Carlos
06:14 queued 04:40
created

Collection   F

Complexity

Total Complexity 149

Size/Duplication

Total Lines 1309
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 99.43%

Importance

Changes 0
Metric Value
dl 0
loc 1309
ccs 349
cts 351
cp 0.9943
rs 0.8
c 0
b 0
f 0
wmc 149
lcom 1
cbo 5

83 Methods

Rating   Name   Duplication   Size   Complexity  
A crossJoin() 0 6 1
A diffUsing() 0 4 1
A get() 0 8 2
A intersect() 0 4 1
A keys() 0 4 1
A map() 0 8 1
A merge() 0 4 1
A prepend() 0 6 1
A pull() 0 4 1
A shuffle() 0 4 1
A skip() 0 4 1
A sortByDesc() 0 4 1
A values() 0 4 1
A getIterator() 0 4 1
A add() 0 6 1
A offsetExists() 0 4 1
A offsetUnset() 0 4 1
A __construct() 0 4 1
A times() 0 12 3
A all() 0 4 1
A lazy() 0 4 1
A avg() 0 14 2
A median() 0 23 4
A mode() 0 22 4
A collapse() 0 4 1
A contains() 0 14 3
A diff() 0 4 1
A diffAssoc() 0 4 1
A diffAssocUsing() 0 4 1
A diffKeys() 0 4 1
A diffKeysUsing() 0 4 1
A duplicates() 0 20 4
A duplicatesStrict() 0 4 1
A duplicateComparator() 0 12 2
A except() 0 10 3
A filter() 0 8 2
A first() 0 4 1
A flatten() 0 4 1
A flip() 0 4 1
A forget() 0 8 2
B groupBy() 0 38 9
A keyBy() 0 18 3
A has() 0 12 4
A implode() 0 10 3
A intersectByKeys() 0 6 1
A isEmpty() 0 4 1
A join() 0 22 4
A last() 0 4 1
A pluck() 0 4 1
A mapToDictionary() 0 20 3
A mapWithKeys() 0 14 3
A mergeRecursive() 0 4 1
A combine() 0 4 1
A union() 0 4 1
A nth() 0 16 3
A only() 0 14 4
A pop() 0 4 1
A push() 0 6 1
A concat() 0 10 2
A put() 0 6 1
A random() 0 8 2
A reduce() 0 4 1
A replace() 0 4 1
A replaceRecursive() 0 4 1
A reverse() 0 4 1
A search() 0 14 4
A shift() 0 4 1
A slice() 0 4 1
A split() 0 30 5
A chunk() 0 14 3
A sort() 0 10 2
A sortBy() 0 25 4
A sortKeys() 0 8 2
A sortKeysDesc() 0 4 1
A splice() 0 8 2
A take() 0 8 2
A transform() 0 6 1
A zip() 0 12 1
A pad() 0 4 1
A count() 0 4 1
A toBase() 0 4 1
A offsetGet() 0 4 1
A offsetSet() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like Collection often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Collection, and based on these observations, apply Extract Interface, too.

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 344
    public function __construct($items = [])
29
    {
30 344
        $this->items = $this->getArrayableItems($items);
31 344
    }
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 1
    public static function times($number, callable $callback = null)
41
    {
42 1
        if ($number < 1) {
43 1
            return new static;
44
        }
45
46 1
        if (is_null($callback)) {
47 1
            return new static(range(1, $number));
48
        }
49
50 1
        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 217
    public function all()
59
    {
60 217
        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 1
    public function lazy()
69
    {
70 1
        return new LazyCollection($this->items);
71
    }
72
73
    /**
74
     * Get the average value of a given key.
75
     *
76
     * @param  callable|string|null  $callback
77
     * @return mixed
78
     */
79 8
    public function avg($callback = null)
80
    {
81 8
        $callback = $this->valueRetriever($callback);
82
83
        $items = $this->map(function ($value) use ($callback) {
84 8
            return $callback($value);
85
        })->filter(function ($value) {
86 8
            return ! is_null($value);
87 8
        });
88
89 8
        if ($count = $items->count()) {
90 8
            return $items->sum() / $count;
91
        }
92 2
    }
93
94
    /**
95
     * Get the median of a given key.
96
     *
97
     * @param  string|array|null $key
98
     * @return mixed
99
     */
100 12
    public function median($key = null)
101
    {
102 12
        $values = (isset($key) ? $this->pluck($key) : $this)
103
            ->filter(function ($item) {
104 10
                return ! is_null($item);
105 12
            })->sort()->values();
106
107 12
        $count = $values->count();
108
109 12
        if ($count === 0) {
110 2
            return;
111
        }
112
113 10
        $middle = (int) ($count / 2);
114
115 10
        if ($count % 2) {
116 4
            return $values->get($middle);
117
        }
118
119 6
        return (new static([
120 6
            $values->get($middle - 1), $values->get($middle),
121 6
        ]))->average();
122
    }
123
124
    /**
125
     * Get the mode of a given key.
126
     *
127
     * @param  string|array|null  $key
128
     * @return array|null
129
     */
130 8
    public function mode($key = null)
131
    {
132 8
        if ($this->count() === 0) {
133 2
            return;
134
        }
135
136 6
        $collection = isset($key) ? $this->pluck($key) : $this;
137
138 6
        $counts = new self;
139
140
        $collection->each(function ($value) use ($counts) {
141 6
            $counts[$value] = isset($counts[$value]) ? $counts[$value] + 1 : 1;
142 6
        });
143
144 6
        $sorted = $counts->sort();
145
146 6
        $highestValue = $sorted->last();
147
148
        return $sorted->filter(function ($value) use ($highestValue) {
149 6
            return $value == $highestValue;
150 6
        })->sort()->keys()->all();
151
    }
152
153
    /**
154
     * Collapse the collection of items into a single array.
155
     *
156
     * @return static
157
     */
158 3
    public function collapse()
159
    {
160 3
        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
     * @param  mixed  $operator
168
     * @param  mixed  $value
169
     * @return bool
170
     */
171 5
    public function contains($key, $operator = null, $value = null)
172
    {
173 5
        if (func_num_args() === 1) {
174 5
            if ($this->useAsCallable($key)) {
175 5
                $placeholder = new stdClass;
176
177 5
                return $this->first($key, $placeholder) !== $placeholder;
178
            }
179
180 2
            return in_array($key, $this->items);
181
        }
182
183 3
        return $this->contains($this->operatorForWhere(...func_get_args()));
184
    }
185
186
    /**
187
     * Cross join with the given lists, returning all possible permutations.
188
     *
189
     * @param  mixed  ...$lists
190
     * @return static
191
     */
192 2
    public function crossJoin(...$lists)
193
    {
194 2
        return new static(Arr::crossJoin(
195 2
            $this->items, ...array_map([$this, 'getArrayableItems'], $lists)
196
        ));
197
    }
198
199
    /**
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 6
    public function diff($items)
206
    {
207 6
        return new static(array_diff($this->items, $this->getArrayableItems($items)));
208
    }
209
210
    /**
211
     * Get the items in the collection that are not present in the given items.
212
     *
213
     * @param  mixed  $items
214
     * @param  callable  $callback
215
     * @return static
216
     */
217 4
    public function diffUsing($items, callable $callback)
218
    {
219 4
        return new static(array_udiff($this->items, $this->getArrayableItems($items), $callback));
220
    }
221
222
    /**
223
     * Get the items in the collection whose keys and values are not present in the given items.
224
     *
225
     * @param  mixed  $items
226
     * @return static
227
     */
228 4
    public function diffAssoc($items)
229
    {
230 4
        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
     * @param  mixed  $items
237
     * @param  callable  $callback
238
     * @return static
239
     */
240 2
    public function diffAssocUsing($items, callable $callback)
241
    {
242 2
        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
     * @return static
250
     */
251 4
    public function diffKeys($items)
252
    {
253 4
        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
     */
263 2
    public function diffKeysUsing($items, callable $callback)
264
    {
265 2
        return new static(array_diff_ukey($this->items, $this->getArrayableItems($items), $callback));
266
    }
267
268
    /**
269
     * Retrieve duplicate items from the collection.
270
     *
271
     * @param  callable|null  $callback
272
     * @param  bool  $strict
273
     * @return static
274
     */
275 8
    public function duplicates($callback = null, $strict = false)
276
    {
277 8
        $items = $this->map($this->valueRetriever($callback));
278
279 8
        $uniqueItems = $items->unique(null, $strict);
280
281 8
        $compare = $this->duplicateComparator($strict);
282
283 8
        $duplicates = new static;
284
285 8
        foreach ($items as $key => $value) {
286 8
            if ($uniqueItems->isNotEmpty() && $compare($value, $uniqueItems->first())) {
287 8
                $uniqueItems->shift();
288
            } else {
289 8
                $duplicates[$key] = $value;
290
            }
291
        }
292
293 8
        return $duplicates;
294
    }
295
296
    /**
297
     * Retrieve duplicate items from the collection using strict comparison.
298
     *
299
     * @param  callable|null  $callback
300
     * @return static
301
     */
302 2
    public function duplicatesStrict($callback = null)
303
    {
304 2
        return $this->duplicates($callback, true);
305
    }
306
307
    /**
308
     * Get the comparison function to detect duplicates.
309
     *
310
     * @param  bool  $strict
311
     * @return \Closure
312
     */
313 8
    protected function duplicateComparator($strict)
314
    {
315 8
        if ($strict) {
316
            return function ($a, $b) {
317 2
                return $a === $b;
318 2
            };
319
        }
320
321
        return function ($a, $b) {
322 6
            return $a == $b;
323 6
        };
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 4
    public function except($keys)
333
    {
334 4
        if ($keys instanceof Enumerable) {
335 4
            $keys = $keys->all();
336 2
        } elseif (! is_array($keys)) {
337 2
            $keys = func_get_args();
338
        }
339
340 4
        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
     * @return static
348
     */
349 50
    public function filter(callable $callback = null)
350
    {
351 50
        if ($callback) {
352 50
            return new static(Arr::where($this->items, $callback));
353
        }
354
355 1
        return new static(array_filter($this->items));
356
    }
357
358
    /**
359
     * Get the first item from the collection passing the given truth test.
360
     *
361
     * @param  callable|null  $callback
362
     * @param  mixed  $default
363
     * @return mixed
364
     */
365 25
    public function first(callable $callback = null, $default = null)
366
    {
367 25
        return Arr::first($this->items, $callback, $default);
368
    }
369
370
    /**
371
     * Get a flattened array of the items in the collection.
372
     *
373
     * @param  int  $depth
374
     * @return static
375
     */
376 3
    public function flatten($depth = INF)
377
    {
378 3
        return new static(Arr::flatten($this->items, $depth));
379
    }
380
381
    /**
382
     * Flip the items in the collection.
383
     *
384
     * @return static
385
     */
386 1
    public function flip()
387
    {
388 1
        return new static(array_flip($this->items));
389
    }
390
391
    /**
392
     * Remove an item from the collection by key.
393
     *
394
     * @param  string|array  $keys
395
     * @return $this
396
     */
397 2
    public function forget($keys)
398
    {
399 2
        foreach ((array) $keys as $key) {
400 2
            $this->offsetUnset($key);
401
        }
402
403 2
        return $this;
404
    }
405
406
    /**
407
     * Get an item from the collection by key.
408
     *
409
     * @param  mixed  $key
410
     * @param  mixed  $default
411
     * @return mixed
412
     */
413 17
    public function get($key, $default = null)
414
    {
415 17
        if ($this->offsetExists($key)) {
416 16
            return $this->items[$key];
417
        }
418
419 1
        return value($default);
420
    }
421
422
    /**
423
     * Group an associative array by a field or using a callback.
424
     *
425
     * @param  array|callable|string  $groupBy
426
     * @param  bool  $preserveKeys
427
     * @return static
428
     */
429 20
    public function groupBy($groupBy, $preserveKeys = false)
430
    {
431 20
        if (is_array($groupBy)) {
432 2
            $nextGroups = $groupBy;
433
434 2
            $groupBy = array_shift($nextGroups);
435
        }
436
437 20
        $groupBy = $this->valueRetriever($groupBy);
438
439 20
        $results = [];
440
441 20
        foreach ($this->items as $key => $value) {
442 20
            $groupKeys = $groupBy($value, $key);
443
444 20
            if (! is_array($groupKeys)) {
445 16
                $groupKeys = [$groupKeys];
446
            }
447
448 20
            foreach ($groupKeys as $groupKey) {
449 20
                $groupKey = is_bool($groupKey) ? (int) $groupKey : $groupKey;
450
451 20
                if (! array_key_exists($groupKey, $results)) {
452 20
                    $results[$groupKey] = new static;
453
                }
454
455 20
                $results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
456
            }
457
        }
458
459 20
        $result = new static($results);
460
461 20
        if (! empty($nextGroups)) {
462 2
            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
465 20
        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
     */
474 4
    public function keyBy($keyBy)
475
    {
476 4
        $keyBy = $this->valueRetriever($keyBy);
477
478 4
        $results = [];
479
480 4
        foreach ($this->items as $key => $item) {
481 4
            $resolvedKey = $keyBy($item, $key);
482
483 4
            if (is_object($resolvedKey)) {
484 1
                $resolvedKey = (string) $resolvedKey;
485
            }
486
487 4
            $results[$resolvedKey] = $item;
488
        }
489
490 4
        return new static($results);
491
    }
492
493
    /**
494
     * Determine if an item exists in the collection by key.
495
     *
496
     * @param  mixed  $key
497
     * @return bool
498
     */
499 2
    public function has($key)
500
    {
501 2
        $keys = is_array($key) ? $key : func_get_args();
502
503 2
        foreach ($keys as $value) {
504 2
            if (! $this->offsetExists($value)) {
505 2
                return false;
506
            }
507
        }
508
509 2
        return true;
510
    }
511
512
    /**
513
     * Concatenate values of a given key as a string.
514
     *
515
     * @param  string  $value
516
     * @param  string  $glue
517
     * @return string
518
     */
519 4
    public function implode($value, $glue = null)
520
    {
521 4
        $first = $this->first();
522
523 4
        if (is_array($first) || is_object($first)) {
524 2
            return implode($glue, $this->pluck($value)->all());
525
        }
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 4
    public function intersect($items)
537
    {
538 4
        return new static(array_intersect($this->items, $this->getArrayableItems($items)));
539
    }
540
541
    /**
542
     * Intersect the collection with the given items by key.
543
     *
544
     * @param  mixed  $items
545
     * @return static
546
     */
547 4
    public function intersectByKeys($items)
548
    {
549 4
        return new static(array_intersect_key(
550 4
            $this->items, $this->getArrayableItems($items)
551
        ));
552
    }
553
554
    /**
555
     * Determine if the collection is empty or not.
556
     *
557
     * @return bool
558
     */
559 34
    public function isEmpty()
560
    {
561 34
        return empty($this->items);
562
    }
563
564
    /**
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 2
    public function join($glue, $finalGlue = '')
572
    {
573 2
        if ($finalGlue === '') {
574 2
            return $this->implode($glue);
575
        }
576
577 2
        $count = $this->count();
578
579 2
        if ($count === 0) {
580 2
            return '';
581
        }
582
583 2
        if ($count === 1) {
584 2
            return $this->last();
585
        }
586
587 2
        $collection = new static($this->items);
588
589 2
        $finalItem = $collection->pop();
590
591 2
        return $collection->implode($glue).$finalGlue.$finalItem;
592
    }
593
594
    /**
595
     * Get the keys of the collection items.
596
     *
597
     * @return static
598
     */
599 9
    public function keys()
600
    {
601 9
        return new static(array_keys($this->items));
602
    }
603
604
    /**
605
     * Get the last item from the collection.
606
     *
607
     * @param  callable|null  $callback
608
     * @param  mixed  $default
609
     * @return mixed
610
     */
611 12
    public function last(callable $callback = null, $default = null)
612
    {
613 12
        return Arr::last($this->items, $callback, $default);
614
    }
615
616
    /**
617
     * Get the values of a given key.
618
     *
619
     * @param  string|array  $value
620
     * @param  string|null  $key
621
     * @return static
622
     */
623 16
    public function pluck($value, $key = null)
624
    {
625 16
        return new static(Arr::pluck($this->items, $value, $key));
626
    }
627
628
    /**
629
     * Run a map over each of the items.
630
     *
631
     * @param  callable  $callback
632
     * @return static
633
     */
634 101
    public function map(callable $callback)
635
    {
636 101
        $keys = array_keys($this->items);
637
638 101
        $items = array_map($callback, $this->items, $keys);
639
640 101
        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
     * @param  callable  $callback
649
     * @return static
650
     */
651 8
    public function mapToDictionary(callable $callback)
652
    {
653 8
        $dictionary = [];
654
655 8
        foreach ($this->items as $key => $item) {
656 8
            $pair = $callback($item, $key);
657
658 8
            $key = key($pair);
659
660 8
            $value = reset($pair);
661
662 8
            if (! isset($dictionary[$key])) {
663 8
                $dictionary[$key] = [];
664
            }
665
666 8
            $dictionary[$key][] = $value;
667
        }
668
669 8
        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
     * @param  callable  $callback
678
     * @return static
679
     */
680 5
    public function mapWithKeys(callable $callback)
681
    {
682 5
        $result = [];
683
684 5
        foreach ($this->items as $key => $value) {
685 5
            $assoc = $callback($value, $key);
686
687 5
            foreach ($assoc as $mapKey => $mapValue) {
688 5
                $result[$mapKey] = $mapValue;
689
            }
690
        }
691
692 5
        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 6
    public function merge($items)
702
    {
703 6
        return new static(array_merge($this->items, $this->getArrayableItems($items)));
704
    }
705
706
    /**
707
     * Recursively merge the collection with the given items.
708
     *
709
     * @param  mixed  $items
710
     * @return static
711
     */
712 6
    public function mergeRecursive($items)
713
    {
714 6
        return new static(array_merge_recursive($this->items, $this->getArrayableItems($items)));
715
    }
716
717
    /**
718
     * Create a collection by using this collection for keys and another for its values.
719
     *
720
     * @param  mixed  $values
721
     * @return static
722
     */
723 2
    public function combine($values)
724
    {
725 2
        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
     * @return static
733
     */
734 6
    public function union($items)
735
    {
736 6
        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
     * @param  int  $offset
744
     * @return static
745
     */
746 1
    public function nth($step, $offset = 0)
747
    {
748 1
        $new = [];
749
750 1
        $position = 0;
751
752 1
        foreach ($this->items as $item) {
753 1
            if ($position % $step === $offset) {
754 1
                $new[] = $item;
755
            }
756
757 1
            $position++;
758
        }
759
760 1
        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 1
    public function only($keys)
770
    {
771 1
        if (is_null($keys)) {
772 1
            return new static($this->items);
773
        }
774
775 1
        if ($keys instanceof Enumerable) {
776 1
            $keys = $keys->all();
777
        }
778
779 1
        $keys = is_array($keys) ? $keys : func_get_args();
780
781 1
        return new static(Arr::only($this->items, $keys));
782
    }
783
784
    /**
785
     * Get and remove the last item from the collection.
786
     *
787
     * @return mixed
788
     */
789 3
    public function pop()
790
    {
791 3
        return array_pop($this->items);
792
    }
793
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 2
    public function prepend($value, $key = null)
802
    {
803 2
        $this->items = Arr::prepend($this->items, $value, $key);
804
805 2
        return $this;
806
    }
807
808
    /**
809
     * Push an item onto the end of the collection.
810
     *
811
     * @param  mixed  $value
812
     * @return $this
813
     */
814 27
    public function push($value)
815
    {
816 27
        $this->items[] = $value;
817
818 27
        return $this;
819
    }
820
821
    /**
822
     * Push all of the given items onto the collection.
823
     *
824
     * @param  iterable  $source
825
     * @return static
826
     */
827 15
    public function concat($source)
828
    {
829 15
        $result = new static($this);
830
831 15
        foreach ($source as $item) {
832 15
            $result->push($item);
833
        }
834
835 15
        return $result;
836
    }
837
838
    /**
839
     * Get and remove an item from the collection.
840
     *
841
     * @param  mixed  $key
842
     * @param  mixed  $default
843
     * @return mixed
844
     */
845 3
    public function pull($key, $default = null)
846
    {
847 3
        return Arr::pull($this->items, $key, $default);
848
    }
849
850
    /**
851
     * Put an item in the collection by key.
852
     *
853
     * @param  mixed  $key
854
     * @param  mixed  $value
855
     * @return $this
856
     */
857 3
    public function put($key, $value)
858
    {
859 3
        $this->offsetSet($key, $value);
860
861 3
        return $this;
862
    }
863
864
    /**
865
     * Get one or a specified number of items randomly from the collection.
866
     *
867
     * @param  int|null  $number
868
     * @return static|mixed
869
     *
870
     * @throws \InvalidArgumentException
871
     */
872 6
    public function random($number = null)
873
    {
874 6
        if (is_null($number)) {
875 2
            return Arr::random($this->items);
876
        }
877
878 6
        return new static(Arr::random($this->items, $number));
879
    }
880
881
    /**
882
     * Reduce the collection to a single value.
883
     *
884
     * @param  callable  $callback
885
     * @param  mixed  $initial
886
     * @return mixed
887
     */
888 15
    public function reduce(callable $callback, $initial = null)
889
    {
890 15
        return array_reduce($this->items, $callback, $initial);
891
    }
892
893
    /**
894
     * Replace the collection items with the given items.
895
     *
896
     * @param  mixed  $items
897
     * @return static
898
     */
899 3
    public function replace($items)
900
    {
901 3
        return new static(array_replace($this->items, $this->getArrayableItems($items)));
902
    }
903
904
    /**
905
     * Recursively replace the collection items with the given items.
906
     *
907
     * @param  mixed  $items
908
     * @return static
909
     */
910 6
    public function replaceRecursive($items)
911
    {
912 6
        return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
913
    }
914
915
    /**
916
     * Reverse items order.
917
     *
918
     * @return static
919
     */
920 2
    public function reverse()
921
    {
922 2
        return new static(array_reverse($this->items, true));
923
    }
924
925
    /**
926
     * Search the collection for a given value and return the corresponding key if successful.
927
     *
928
     * @param  mixed  $value
929
     * @param  bool  $strict
930
     * @return mixed
931
     */
932 3
    public function search($value, $strict = false)
933
    {
934 3
        if (! $this->useAsCallable($value)) {
935 3
            return array_search($value, $this->items, $strict);
936
        }
937
938 2
        foreach ($this->items as $key => $item) {
939 2
            if ($value($item, $key)) {
940 1
                return $key;
941
            }
942
        }
943
944 1
        return false;
945
    }
946
947
    /**
948
     * Get and remove the first item from the collection.
949
     *
950
     * @return mixed
951
     */
952 9
    public function shift()
953
    {
954 9
        return array_shift($this->items);
955
    }
956
957
    /**
958
     * Shuffle the items in the collection.
959
     *
960
     * @param  int  $seed
961
     * @return static
962
     */
963 1
    public function shuffle($seed = null)
964
    {
965 1
        return new static(Arr::shuffle($this->items, $seed));
966
    }
967
968
    /**
969
     * Skip the first {$count} items.
970
     *
971
     * @param  int  $count
972
     * @return static
973
     */
974 1
    public function skip($count)
975
    {
976 1
        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
     */
986 16
    public function slice($offset, $length = null)
987
    {
988 16
        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 14
    public function split($numberOfGroups)
998
    {
999 14
        if ($this->isEmpty()) {
1000 2
            return new static;
1001
        }
1002
1003 12
        $groups = new static;
1004
1005 12
        $groupSize = floor($this->count() / $numberOfGroups);
1006
1007 12
        $remain = $this->count() % $numberOfGroups;
1008
1009 12
        $start = 0;
1010
1011 12
        for ($i = 0; $i < $numberOfGroups; $i++) {
1012 12
            $size = $groupSize;
1013
1014 12
            if ($i < $remain) {
1015 10
                $size++;
1016
            }
1017
1018 12
            if ($size) {
1019 12
                $groups->push(new static(array_slice($this->items, $start, $size)));
1020
1021 12
                $start += $size;
1022
            }
1023
        }
1024
1025 12
        return $groups;
1026
    }
1027
1028
    /**
1029
     * Chunk the collection into chunks of the given size.
1030
     *
1031
     * @param  int  $size
1032
     * @return static
1033
     */
1034 3
    public function chunk($size)
1035
    {
1036 3
        if ($size <= 0) {
1037 2
            return new static;
1038
        }
1039
1040 1
        $chunks = [];
1041
1042 1
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1043 1
            $chunks[] = new static($chunk);
1044
        }
1045
1046 1
        return new static($chunks);
1047
    }
1048
1049
    /**
1050
     * Sort through each item with a callback.
1051
     *
1052
     * @param  callable|null  $callback
1053
     * @return static
1054
     */
1055 22
    public function sort(callable $callback = null)
1056
    {
1057 22
        $items = $this->items;
1058
1059 22
        $callback
1060 2
            ? uasort($items, $callback)
1061 20
            : asort($items);
1062
1063 22
        return new static($items);
1064
    }
1065
1066
    /**
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 9
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1075
    {
1076 9
        $results = [];
1077
1078 9
        $callback = $this->valueRetriever($callback);
1079
1080
        // First we will loop through the items and get the comparator from a callback
1081
        // 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 9
        foreach ($this->items as $key => $value) {
1084 9
            $results[$key] = $callback($value, $key);
1085
        }
1086
1087 9
        $descending ? arsort($results, $options)
1088 9
            : 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
        // to the sorted version. Then we'll just return the collection instance.
1093 9
        foreach (array_keys($results) as $key) {
1094 9
            $results[$key] = $this->items[$key];
1095
        }
1096
1097 9
        return new static($results);
1098
    }
1099
1100
    /**
1101
     * Sort the collection in descending order using the given callback.
1102
     *
1103
     * @param  callable|string  $callback
1104
     * @param  int  $options
1105
     * @return static
1106
     */
1107 2
    public function sortByDesc($callback, $options = SORT_REGULAR)
1108
    {
1109 2
        return $this->sortBy($callback, $options, true);
1110
    }
1111
1112
    /**
1113
     * Sort the collection keys.
1114
     *
1115
     * @param  int  $options
1116
     * @param  bool  $descending
1117
     * @return static
1118
     */
1119 4
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1120
    {
1121 4
        $items = $this->items;
1122
1123 4
        $descending ? krsort($items, $options) : ksort($items, $options);
1124
1125 4
        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 2
    public function sortKeysDesc($options = SORT_REGULAR)
1135
    {
1136 2
        return $this->sortKeys($options, true);
1137
    }
1138
1139
    /**
1140
     * Splice a portion of the underlying collection array.
1141
     *
1142
     * @param  int  $offset
1143
     * @param  int|null  $length
1144
     * @param  mixed  $replacement
1145
     * @return static
1146
     */
1147 1
    public function splice($offset, $length = null, $replacement = [])
1148
    {
1149 1
        if (func_num_args() === 1) {
1150 1
            return new static(array_splice($this->items, $offset));
1151
        }
1152
1153 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1154
    }
1155
1156
    /**
1157
     * Take the first or last {$limit} items.
1158
     *
1159
     * @param  int  $limit
1160
     * @return static
1161
     */
1162 3
    public function take($limit)
1163
    {
1164 3
        if ($limit < 0) {
1165 2
            return $this->slice($limit, abs($limit));
1166
        }
1167
1168 1
        return $this->slice(0, $limit);
1169
    }
1170
1171
    /**
1172
     * Transform each item in the collection using a callback.
1173
     *
1174
     * @param  callable  $callback
1175
     * @return $this
1176
     */
1177 1
    public function transform(callable $callback)
1178
    {
1179 1
        $this->items = $this->map($callback)->all();
1180
1181 1
        return $this;
1182
    }
1183
1184
    /**
1185
     * Reset the keys on the underlying array.
1186
     *
1187
     * @return static
1188
     */
1189 52
    public function values()
1190
    {
1191 52
        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
     * @param  mixed ...$items
1201
     * @return static
1202
     */
1203 1
    public function zip($items)
1204
    {
1205
        $arrayableItems = array_map(function ($items) {
1206 1
            return $this->getArrayableItems($items);
1207 1
        }, func_get_args());
1208
1209
        $params = array_merge([function () {
1210 1
            return new static(func_get_args());
1211 1
        }, $this->items], $arrayableItems);
1212
1213 1
        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
     */
1223 2
    public function pad($size, $value)
1224
    {
1225 2
        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 97
    public function getIterator()
1234
    {
1235 97
        return new ArrayIterator($this->items);
1236
    }
1237
1238
    /**
1239
     * Count the number of items in the collection.
1240
     *
1241
     * @return int
1242
     */
1243 49
    public function count()
1244
    {
1245 49
        return count($this->items);
1246
    }
1247
1248
    /**
1249
     * Add an item to the collection.
1250
     *
1251
     * @param  mixed  $item
1252
     * @return $this
1253
     */
1254 1
    public function add($item)
1255
    {
1256 1
        $this->items[] = $item;
1257
1258 1
        return $this;
1259
    }
1260
1261
    /**
1262
     * Get a base Support collection instance from this collection.
1263
     *
1264
     * @return \IlluminateAgnostic\Arr\Support\Collection
1265
     */
1266
    public function toBase()
1267
    {
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
     */
1277 29
    public function offsetExists($key)
1278
    {
1279 29
        return array_key_exists($key, $this->items);
1280
    }
1281
1282
    /**
1283
     * Get an item at a given offset.
1284
     *
1285
     * @param  mixed  $key
1286
     * @return mixed
1287
     */
1288 9
    public function offsetGet($key)
1289
    {
1290 9
        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
     * @return void
1299
     */
1300 43
    public function offsetSet($key, $value)
1301
    {
1302 43
        if (is_null($key)) {
1303 19
            $this->items[] = $value;
1304
        } else {
1305 26
            $this->items[$key] = $value;
1306
        }
1307 43
    }
1308
1309
    /**
1310
     * Unset the item at a given offset.
1311
     *
1312
     * @param  string  $key
1313
     * @return void
1314
     */
1315 4
    public function offsetUnset($key)
1316
    {
1317 4
        unset($this->items[$key]);
1318 4
    }
1319
}
1320