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