Subversion-Projekte lars-tiefland.laravel_shop

Revision

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