Completed
Push — master ( 91c709...1f6826 )
by Antonio Carlos
06:01
created

Collection::sortDesc()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 10
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 352
    public function __construct($items = [])
29
    {
30 352
        $this->items = $this->getArrayableItems($items);
31 352
    }
32
33
    /**
34
     * Create a new collection by invoking the callback a given amount of times.
35
     *
36
     * @param  int  $number
37
     * @param  callable|null  $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 224
    public function all()
59
    {
60 224
        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));
0 ignored issues
show
Documentation introduced by
$this->items is of type array, but the function expects a object<IlluminateAgnostic\Arr\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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, using the callback.
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, using the callback.
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, using the callback.
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 54
    public function filter(callable $callback = null)
350
    {
351 54
        if ($callback) {
352 54
            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);
0 ignored issues
show
Documentation introduced by
$this->items is of type array, but the function expects a object<IlluminateAgnostic\Arr\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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));
0 ignored issues
show
Documentation introduced by
$this->items is of type array, but the function expects a object<IlluminateAgnostic\Arr\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
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|null  $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));
0 ignored issues
show
Documentation introduced by
$this->items is of type array, but the function expects a object<IlluminateAgnostic\Arr\Support\iterable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
626
    }
627
628
    /**
629
     * Run a map over each of the items.
630
     *
631
     * @param  callable  $callback
632
     * @return static
633
     */
634 103
    public function map(callable $callback)
635
    {
636 103
        $keys = array_keys($this->items);
637
638 103
        $items = array_map($callback, $this->items, $keys);
639
640 103
        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 one or more items onto the end of the collection.
810
     *
811
     * @param  mixed  $values [optional]
812
     * @return $this
813
     */
814 29
    public function push(...$values)
815
    {
816 29
        foreach ($values as $value) {
817 29
            $this->items[] = $value;
818
        }
819
820 29
        return $this;
821
    }
822
823
    /**
824
     * Push all of the given items onto the collection.
825
     *
826
     * @param  iterable  $source
827
     * @return static
828
     */
829 15
    public function concat($source)
830
    {
831 15
        $result = new static($this);
832
833 15
        foreach ($source as $item) {
834 15
            $result->push($item);
835
        }
836
837 15
        return $result;
838
    }
839
840
    /**
841
     * Get and remove an item from the collection.
842
     *
843
     * @param  mixed  $key
844
     * @param  mixed  $default
845
     * @return mixed
846
     */
847 3
    public function pull($key, $default = null)
848
    {
849 3
        return Arr::pull($this->items, $key, $default);
850
    }
851
852
    /**
853
     * Put an item in the collection by key.
854
     *
855
     * @param  mixed  $key
856
     * @param  mixed  $value
857
     * @return $this
858
     */
859 3
    public function put($key, $value)
860
    {
861 3
        $this->offsetSet($key, $value);
862
863 3
        return $this;
864
    }
865
866
    /**
867
     * Get one or a specified number of items randomly from the collection.
868
     *
869
     * @param  int|null  $number
870
     * @return static|mixed
871
     *
872
     * @throws \InvalidArgumentException
873
     */
874 6
    public function random($number = null)
875
    {
876 6
        if (is_null($number)) {
877 2
            return Arr::random($this->items);
878
        }
879
880 6
        return new static(Arr::random($this->items, $number));
881
    }
882
883
    /**
884
     * Reduce the collection to a single value.
885
     *
886
     * @param  callable  $callback
887
     * @param  mixed  $initial
888
     * @return mixed
889
     */
890 15
    public function reduce(callable $callback, $initial = null)
891
    {
892 15
        return array_reduce($this->items, $callback, $initial);
893
    }
894
895
    /**
896
     * Replace the collection items with the given items.
897
     *
898
     * @param  mixed  $items
899
     * @return static
900
     */
901 3
    public function replace($items)
902
    {
903 3
        return new static(array_replace($this->items, $this->getArrayableItems($items)));
904
    }
905
906
    /**
907
     * Recursively replace the collection items with the given items.
908
     *
909
     * @param  mixed  $items
910
     * @return static
911
     */
912 6
    public function replaceRecursive($items)
913
    {
914 6
        return new static(array_replace_recursive($this->items, $this->getArrayableItems($items)));
915
    }
916
917
    /**
918
     * Reverse items order.
919
     *
920
     * @return static
921
     */
922 2
    public function reverse()
923
    {
924 2
        return new static(array_reverse($this->items, true));
925
    }
926
927
    /**
928
     * Search the collection for a given value and return the corresponding key if successful.
929
     *
930
     * @param  mixed  $value
931
     * @param  bool  $strict
932
     * @return mixed
933
     */
934 3
    public function search($value, $strict = false)
935
    {
936 3
        if (! $this->useAsCallable($value)) {
937 3
            return array_search($value, $this->items, $strict);
938
        }
939
940 2
        foreach ($this->items as $key => $item) {
941 2
            if ($value($item, $key)) {
942 1
                return $key;
943
            }
944
        }
945
946 1
        return false;
947
    }
948
949
    /**
950
     * Get and remove the first item from the collection.
951
     *
952
     * @return mixed
953
     */
954 9
    public function shift()
955
    {
956 9
        return array_shift($this->items);
957
    }
958
959
    /**
960
     * Shuffle the items in the collection.
961
     *
962
     * @param  int|null  $seed
963
     * @return static
964
     */
965 1
    public function shuffle($seed = null)
966
    {
967 1
        return new static(Arr::shuffle($this->items, $seed));
968
    }
969
970
    /**
971
     * Skip the first {$count} items.
972
     *
973
     * @param  int  $count
974
     * @return static
975
     */
976 1
    public function skip($count)
977
    {
978 1
        return $this->slice($count);
979
    }
980
981
    /**
982
     * Slice the underlying collection array.
983
     *
984
     * @param  int  $offset
985
     * @param  int|null  $length
986
     * @return static
987
     */
988 16
    public function slice($offset, $length = null)
989
    {
990 16
        return new static(array_slice($this->items, $offset, $length, true));
991
    }
992
993
    /**
994
     * Split a collection into a certain number of groups.
995
     *
996
     * @param  int  $numberOfGroups
997
     * @return static
998
     */
999 14
    public function split($numberOfGroups)
1000
    {
1001 14
        if ($this->isEmpty()) {
1002 2
            return new static;
1003
        }
1004
1005 12
        $groups = new static;
1006
1007 12
        $groupSize = floor($this->count() / $numberOfGroups);
1008
1009 12
        $remain = $this->count() % $numberOfGroups;
1010
1011 12
        $start = 0;
1012
1013 12
        for ($i = 0; $i < $numberOfGroups; $i++) {
1014 12
            $size = $groupSize;
1015
1016 12
            if ($i < $remain) {
1017 10
                $size++;
1018
            }
1019
1020 12
            if ($size) {
1021 12
                $groups->push(new static(array_slice($this->items, $start, $size)));
1022
1023 12
                $start += $size;
1024
            }
1025
        }
1026
1027 12
        return $groups;
1028
    }
1029
1030
    /**
1031
     * Chunk the collection into chunks of the given size.
1032
     *
1033
     * @param  int  $size
1034
     * @return static
1035
     */
1036 3
    public function chunk($size)
1037
    {
1038 3
        if ($size <= 0) {
1039 2
            return new static;
1040
        }
1041
1042 1
        $chunks = [];
1043
1044 1
        foreach (array_chunk($this->items, $size, true) as $chunk) {
1045 1
            $chunks[] = new static($chunk);
1046
        }
1047
1048 1
        return new static($chunks);
1049
    }
1050
1051
    /**
1052
     * Sort through each item with a callback.
1053
     *
1054
     * @param  callable|null  $callback
1055
     * @return static
1056
     */
1057 22
    public function sort($callback = null)
1058
    {
1059 22
        $items = $this->items;
1060
1061 22
        $callback && is_callable($callback)
1062 2
            ? uasort($items, $callback)
1063 20
            : asort($items, $callback);
1064
1065 22
        return new static($items);
1066
    }
1067
1068
    /**
1069
     * Sort items in descending order.
1070
     *
1071
     * @param  int  $options
1072
     * @return static
1073
     */
1074 2
    public function sortDesc($options = SORT_REGULAR)
1075
    {
1076 2
        $items = $this->items;
1077
1078 2
        arsort($items, $options);
1079
1080 2
        return new static($items);
1081
    }
1082
1083
    /**
1084
     * Sort the collection using the given callback.
1085
     *
1086
     * @param  callable|string  $callback
1087
     * @param  int  $options
1088
     * @param  bool  $descending
1089
     * @return static
1090
     */
1091 9
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1092
    {
1093 9
        $results = [];
1094
1095 9
        $callback = $this->valueRetriever($callback);
1096
1097
        // First we will loop through the items and get the comparator from a callback
1098
        // function which we were given. Then, we will sort the returned values and
1099
        // and grab the corresponding values for the sorted keys from this array.
1100 9
        foreach ($this->items as $key => $value) {
1101 9
            $results[$key] = $callback($value, $key);
1102
        }
1103
1104 9
        $descending ? arsort($results, $options)
1105 9
            : asort($results, $options);
1106
1107
        // Once we have sorted all of the keys in the array, we will loop through them
1108
        // and grab the corresponding model so we can set the underlying items list
1109
        // to the sorted version. Then we'll just return the collection instance.
1110 9
        foreach (array_keys($results) as $key) {
1111 9
            $results[$key] = $this->items[$key];
1112
        }
1113
1114 9
        return new static($results);
1115
    }
1116
1117
    /**
1118
     * Sort the collection in descending order using the given callback.
1119
     *
1120
     * @param  callable|string  $callback
1121
     * @param  int  $options
1122
     * @return static
1123
     */
1124 2
    public function sortByDesc($callback, $options = SORT_REGULAR)
1125
    {
1126 2
        return $this->sortBy($callback, $options, true);
1127
    }
1128
1129
    /**
1130
     * Sort the collection keys.
1131
     *
1132
     * @param  int  $options
1133
     * @param  bool  $descending
1134
     * @return static
1135
     */
1136 4
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1137
    {
1138 4
        $items = $this->items;
1139
1140 4
        $descending ? krsort($items, $options) : ksort($items, $options);
1141
1142 4
        return new static($items);
1143
    }
1144
1145
    /**
1146
     * Sort the collection keys in descending order.
1147
     *
1148
     * @param  int  $options
1149
     * @return static
1150
     */
1151 2
    public function sortKeysDesc($options = SORT_REGULAR)
1152
    {
1153 2
        return $this->sortKeys($options, true);
1154
    }
1155
1156
    /**
1157
     * Splice a portion of the underlying collection array.
1158
     *
1159
     * @param  int  $offset
1160
     * @param  int|null  $length
1161
     * @param  mixed  $replacement
1162
     * @return static
1163
     */
1164 1
    public function splice($offset, $length = null, $replacement = [])
1165
    {
1166 1
        if (func_num_args() === 1) {
1167 1
            return new static(array_splice($this->items, $offset));
1168
        }
1169
1170 1
        return new static(array_splice($this->items, $offset, $length, $replacement));
1171
    }
1172
1173
    /**
1174
     * Take the first or last {$limit} items.
1175
     *
1176
     * @param  int  $limit
1177
     * @return static
1178
     */
1179 3
    public function take($limit)
1180
    {
1181 3
        if ($limit < 0) {
1182 2
            return $this->slice($limit, abs($limit));
1183
        }
1184
1185 1
        return $this->slice(0, $limit);
1186
    }
1187
1188
    /**
1189
     * Transform each item in the collection using a callback.
1190
     *
1191
     * @param  callable  $callback
1192
     * @return $this
1193
     */
1194 1
    public function transform(callable $callback)
1195
    {
1196 1
        $this->items = $this->map($callback)->all();
1197
1198 1
        return $this;
1199
    }
1200
1201
    /**
1202
     * Reset the keys on the underlying array.
1203
     *
1204
     * @return static
1205
     */
1206 53
    public function values()
1207
    {
1208 53
        return new static(array_values($this->items));
1209
    }
1210
1211
    /**
1212
     * Zip the collection together with one or more arrays.
1213
     *
1214
     * e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
1215
     *      => [[1, 4], [2, 5], [3, 6]]
1216
     *
1217
     * @param  mixed ...$items
1218
     * @return static
1219
     */
1220 1
    public function zip($items)
1221
    {
1222
        $arrayableItems = array_map(function ($items) {
1223 1
            return $this->getArrayableItems($items);
1224 1
        }, func_get_args());
1225
1226
        $params = array_merge([function () {
1227 1
            return new static(func_get_args());
1228 1
        }, $this->items], $arrayableItems);
1229
1230 1
        return new static(call_user_func_array('array_map', $params));
1231
    }
1232
1233
    /**
1234
     * Pad collection to the specified length with a value.
1235
     *
1236
     * @param  int  $size
1237
     * @param  mixed  $value
1238
     * @return static
1239
     */
1240 2
    public function pad($size, $value)
1241
    {
1242 2
        return new static(array_pad($this->items, $size, $value));
1243
    }
1244
1245
    /**
1246
     * Get an iterator for the items.
1247
     *
1248
     * @return \ArrayIterator
1249
     */
1250 99
    public function getIterator()
1251
    {
1252 99
        return new ArrayIterator($this->items);
1253
    }
1254
1255
    /**
1256
     * Count the number of items in the collection.
1257
     *
1258
     * @return int
1259
     */
1260 49
    public function count()
1261
    {
1262 49
        return count($this->items);
1263
    }
1264
1265
    /**
1266
     * Add an item to the collection.
1267
     *
1268
     * @param  mixed  $item
1269
     * @return $this
1270
     */
1271 1
    public function add($item)
1272
    {
1273 1
        $this->items[] = $item;
1274
1275 1
        return $this;
1276
    }
1277
1278
    /**
1279
     * Get a base Support collection instance from this collection.
1280
     *
1281
     * @return \IlluminateAgnostic\Arr\Support\Collection
1282
     */
1283
    public function toBase()
1284
    {
1285
        return new self($this);
1286
    }
1287
1288
    /**
1289
     * Determine if an item exists at an offset.
1290
     *
1291
     * @param  mixed  $key
1292
     * @return bool
1293
     */
1294 29
    public function offsetExists($key)
1295
    {
1296 29
        return array_key_exists($key, $this->items);
1297
    }
1298
1299
    /**
1300
     * Get an item at a given offset.
1301
     *
1302
     * @param  mixed  $key
1303
     * @return mixed
1304
     */
1305 9
    public function offsetGet($key)
1306
    {
1307 9
        return $this->items[$key];
1308
    }
1309
1310
    /**
1311
     * Set the item at a given offset.
1312
     *
1313
     * @param  mixed  $key
1314
     * @param  mixed  $value
1315
     * @return void
1316
     */
1317 43
    public function offsetSet($key, $value)
1318
    {
1319 43
        if (is_null($key)) {
1320 19
            $this->items[] = $value;
1321
        } else {
1322 26
            $this->items[$key] = $value;
1323
        }
1324 43
    }
1325
1326
    /**
1327
     * Unset the item at a given offset.
1328
     *
1329
     * @param  string  $key
1330
     * @return void
1331
     */
1332 4
    public function offsetUnset($key)
1333
    {
1334 4
        unset($this->items[$key]);
1335 4
    }
1336
}
1337