Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 150 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

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