Subversion-Projekte lars-tiefland.laravel_shop

Revision

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

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Support;
4
 
5
use 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)) {
433
            $callback = function ($value) {
434
                return (bool) $value;
435
            };
436
        }
437
 
438
        return new static(function () use ($callback) {
439
            foreach ($this as $key => $value) {
440
                if ($callback($value, $key)) {
441
                    yield $key => $value;
442
                }
443
            }
444
        });
445
    }
446
 
447
    /**
448
     * Get the first item from the enumerable passing the given truth test.
449
     *
450
     * @template TFirstDefault
451
     *
452
     * @param  (callable(TValue): bool)|null  $callback
453
     * @param  TFirstDefault|(\Closure(): TFirstDefault)  $default
454
     * @return TValue|TFirstDefault
455
     */
456
    public function first(callable $callback = null, $default = null)
457
    {
458
        $iterator = $this->getIterator();
459
 
460
        if (is_null($callback)) {
461
            if (! $iterator->valid()) {
462
                return value($default);
463
            }
464
 
465
            return $iterator->current();
466
        }
467
 
468
        foreach ($iterator as $key => $value) {
469
            if ($callback($value, $key)) {
470
                return $value;
471
            }
472
        }
473
 
474
        return value($default);
475
    }
476
 
477
    /**
478
     * Get a flattened list of the items in the collection.
479
     *
480
     * @param  int  $depth
481
     * @return static<int, mixed>
482
     */
483
    public function flatten($depth = INF)
484
    {
485
        $instance = new static(function () use ($depth) {
486
            foreach ($this as $item) {
487
                if (! is_array($item) && ! $item instanceof Enumerable) {
488
                    yield $item;
489
                } elseif ($depth === 1) {
490
                    yield from $item;
491
                } else {
492
                    yield from (new static($item))->flatten($depth - 1);
493
                }
494
            }
495
        });
496
 
497
        return $instance->values();
498
    }
499
 
500
    /**
501
     * Flip the items in the collection.
502
     *
503
     * @return static<TValue, TKey>
504
     */
505
    public function flip()
506
    {
507
        return new static(function () {
508
            foreach ($this as $key => $value) {
509
                yield $value => $key;
510
            }
511
        });
512
    }
513
 
514
    /**
515
     * Get an item by key.
516
     *
517
     * @template TGetDefault
518
     *
519
     * @param  TKey|null  $key
520
     * @param  TGetDefault|(\Closure(): TGetDefault)  $default
521
     * @return TValue|TGetDefault
522
     */
523
    public function get($key, $default = null)
524
    {
525
        if (is_null($key)) {
526
            return;
527
        }
528
 
529
        foreach ($this as $outerKey => $outerValue) {
530
            if ($outerKey == $key) {
531
                return $outerValue;
532
            }
533
        }
534
 
535
        return value($default);
536
    }
537
 
538
    /**
539
     * Group an associative array by a field or using a callback.
540
     *
541
     * @param  (callable(TValue, TKey): array-key)|array|string  $groupBy
542
     * @param  bool  $preserveKeys
543
     * @return static<array-key, static<array-key, TValue>>
544
     */
545
    public function groupBy($groupBy, $preserveKeys = false)
546
    {
547
        return $this->passthru('groupBy', func_get_args());
548
    }
549
 
550
    /**
551
     * Key an associative array by a field or using a callback.
552
     *
553
     * @param  (callable(TValue, TKey): array-key)|array|string  $keyBy
554
     * @return static<array-key, TValue>
555
     */
556
    public function keyBy($keyBy)
557
    {
558
        return new static(function () use ($keyBy) {
559
            $keyBy = $this->valueRetriever($keyBy);
560
 
561
            foreach ($this as $key => $item) {
562
                $resolvedKey = $keyBy($item, $key);
563
 
564
                if (is_object($resolvedKey)) {
565
                    $resolvedKey = (string) $resolvedKey;
566
                }
567
 
568
                yield $resolvedKey => $item;
569
            }
570
        });
571
    }
572
 
573
    /**
574
     * Determine if an item exists in the collection by key.
575
     *
576
     * @param  mixed  $key
577
     * @return bool
578
     */
579
    public function has($key)
580
    {
581
        $keys = array_flip(is_array($key) ? $key : func_get_args());
582
        $count = count($keys);
583
 
584
        foreach ($this as $key => $value) {
585
            if (array_key_exists($key, $keys) && --$count == 0) {
586
                return true;
587
            }
588
        }
589
 
590
        return false;
591
    }
592
 
593
    /**
594
     * Determine if any of the keys exist in the collection.
595
     *
596
     * @param  mixed  $key
597
     * @return bool
598
     */
599
    public function hasAny($key)
600
    {
601
        $keys = array_flip(is_array($key) ? $key : func_get_args());
602
 
603
        foreach ($this as $key => $value) {
604
            if (array_key_exists($key, $keys)) {
605
                return true;
606
            }
607
        }
608
 
609
        return false;
610
    }
611
 
612
    /**
613
     * Concatenate values of a given key as a string.
614
     *
615
     * @param  callable|string  $value
616
     * @param  string|null  $glue
617
     * @return string
618
     */
619
    public function implode($value, $glue = null)
620
    {
621
        return $this->collect()->implode(...func_get_args());
622
    }
623
 
624
    /**
625
     * Intersect the collection with the given items.
626
     *
627
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
628
     * @return static
629
     */
630
    public function intersect($items)
631
    {
632
        return $this->passthru('intersect', func_get_args());
633
    }
634
 
635
    /**
399 lars 636
     * Intersect the collection with the given items, using the callback.
637
     *
638
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TValue>|iterable<array-key, TValue>  $items
639
     * @param  callable(TValue, TValue): int  $callback
640
     * @return static
641
     */
642
    public function intersectUsing()
643
    {
644
        return $this->passthru('intersectUsing', func_get_args());
645
    }
646
 
647
    /**
648
     * Intersect the collection with the given items with additional index check.
649
     *
650
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
651
     * @return static
652
     */
653
    public function intersectAssoc($items)
654
    {
655
        return $this->passthru('intersectAssoc', func_get_args());
656
    }
657
 
658
    /**
659
     * Intersect the collection with the given items with additional index check, using the callback.
660
     *
661
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TValue>|iterable<array-key, TValue>  $items
662
     * @param  callable(TValue, TValue): int  $callback
663
     * @return static
664
     */
665
    public function intersectAssocUsing($items, callable $callback)
666
    {
667
        return $this->passthru('intersectAssocUsing', func_get_args());
668
    }
669
 
670
    /**
148 lars 671
     * Intersect the collection with the given items by key.
672
     *
673
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
674
     * @return static
675
     */
676
    public function intersectByKeys($items)
677
    {
678
        return $this->passthru('intersectByKeys', func_get_args());
679
    }
680
 
681
    /**
682
     * Determine if the items are empty or not.
683
     *
684
     * @return bool
685
     */
686
    public function isEmpty()
687
    {
688
        return ! $this->getIterator()->valid();
689
    }
690
 
691
    /**
692
     * Determine if the collection contains a single item.
693
     *
694
     * @return bool
695
     */
696
    public function containsOneItem()
697
    {
698
        return $this->take(2)->count() === 1;
699
    }
700
 
701
    /**
702
     * Join all items from the collection using a string. The final items can use a separate glue string.
703
     *
704
     * @param  string  $glue
705
     * @param  string  $finalGlue
706
     * @return string
707
     */
708
    public function join($glue, $finalGlue = '')
709
    {
710
        return $this->collect()->join(...func_get_args());
711
    }
712
 
713
    /**
714
     * Get the keys of the collection items.
715
     *
716
     * @return static<int, TKey>
717
     */
718
    public function keys()
719
    {
720
        return new static(function () {
721
            foreach ($this as $key => $value) {
722
                yield $key;
723
            }
724
        });
725
    }
726
 
727
    /**
728
     * Get the last item from the collection.
729
     *
730
     * @template TLastDefault
731
     *
732
     * @param  (callable(TValue, TKey): bool)|null  $callback
733
     * @param  TLastDefault|(\Closure(): TLastDefault)  $default
734
     * @return TValue|TLastDefault
735
     */
736
    public function last(callable $callback = null, $default = null)
737
    {
738
        $needle = $placeholder = new stdClass;
739
 
740
        foreach ($this as $key => $value) {
741
            if (is_null($callback) || $callback($value, $key)) {
742
                $needle = $value;
743
            }
744
        }
745
 
746
        return $needle === $placeholder ? value($default) : $needle;
747
    }
748
 
749
    /**
750
     * Get the values of a given key.
751
     *
752
     * @param  string|array<array-key, string>  $value
753
     * @param  string|null  $key
754
     * @return static<int, mixed>
755
     */
756
    public function pluck($value, $key = null)
757
    {
758
        return new static(function () use ($value, $key) {
759
            [$value, $key] = $this->explodePluckParameters($value, $key);
760
 
761
            foreach ($this as $item) {
762
                $itemValue = data_get($item, $value);
763
 
764
                if (is_null($key)) {
765
                    yield $itemValue;
766
                } else {
767
                    $itemKey = data_get($item, $key);
768
 
769
                    if (is_object($itemKey) && method_exists($itemKey, '__toString')) {
770
                        $itemKey = (string) $itemKey;
771
                    }
772
 
773
                    yield $itemKey => $itemValue;
774
                }
775
            }
776
        });
777
    }
778
 
779
    /**
780
     * Run a map over each of the items.
781
     *
782
     * @template TMapValue
783
     *
784
     * @param  callable(TValue, TKey): TMapValue  $callback
785
     * @return static<TKey, TMapValue>
786
     */
787
    public function map(callable $callback)
788
    {
789
        return new static(function () use ($callback) {
790
            foreach ($this as $key => $value) {
791
                yield $key => $callback($value, $key);
792
            }
793
        });
794
    }
795
 
796
    /**
797
     * Run a dictionary map over the items.
798
     *
799
     * The callback should return an associative array with a single key/value pair.
800
     *
801
     * @template TMapToDictionaryKey of array-key
802
     * @template TMapToDictionaryValue
803
     *
804
     * @param  callable(TValue, TKey): array<TMapToDictionaryKey, TMapToDictionaryValue>  $callback
805
     * @return static<TMapToDictionaryKey, array<int, TMapToDictionaryValue>>
806
     */
807
    public function mapToDictionary(callable $callback)
808
    {
809
        return $this->passthru('mapToDictionary', func_get_args());
810
    }
811
 
812
    /**
813
     * Run an associative map over each of the items.
814
     *
815
     * The callback should return an associative array with a single key/value pair.
816
     *
817
     * @template TMapWithKeysKey of array-key
818
     * @template TMapWithKeysValue
819
     *
820
     * @param  callable(TValue, TKey): array<TMapWithKeysKey, TMapWithKeysValue>  $callback
821
     * @return static<TMapWithKeysKey, TMapWithKeysValue>
822
     */
823
    public function mapWithKeys(callable $callback)
824
    {
825
        return new static(function () use ($callback) {
826
            foreach ($this as $key => $value) {
827
                yield from $callback($value, $key);
828
            }
829
        });
830
    }
831
 
832
    /**
833
     * Merge the collection with the given items.
834
     *
835
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
836
     * @return static
837
     */
838
    public function merge($items)
839
    {
840
        return $this->passthru('merge', func_get_args());
841
    }
842
 
843
    /**
844
     * Recursively merge the collection with the given items.
845
     *
846
     * @template TMergeRecursiveValue
847
     *
848
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TMergeRecursiveValue>|iterable<TKey, TMergeRecursiveValue>  $items
849
     * @return static<TKey, TValue|TMergeRecursiveValue>
850
     */
851
    public function mergeRecursive($items)
852
    {
853
        return $this->passthru('mergeRecursive', func_get_args());
854
    }
855
 
856
    /**
857
     * Create a collection by using this collection for keys and another for its values.
858
     *
859
     * @template TCombineValue
860
     *
861
     * @param  \IteratorAggregate<array-key, TCombineValue>|array<array-key, TCombineValue>|(callable(): \Generator<array-key, TCombineValue>)  $values
862
     * @return static<TValue, TCombineValue>
863
     */
864
    public function combine($values)
865
    {
866
        return new static(function () use ($values) {
867
            $values = $this->makeIterator($values);
868
 
869
            $errorMessage = 'Both parameters should have an equal number of elements';
870
 
871
            foreach ($this as $key) {
872
                if (! $values->valid()) {
873
                    trigger_error($errorMessage, E_USER_WARNING);
874
 
875
                    break;
876
                }
877
 
878
                yield $key => $values->current();
879
 
880
                $values->next();
881
            }
882
 
883
            if ($values->valid()) {
884
                trigger_error($errorMessage, E_USER_WARNING);
885
            }
886
        });
887
    }
888
 
889
    /**
890
     * Union the collection with the given items.
891
     *
892
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
893
     * @return static
894
     */
895
    public function union($items)
896
    {
897
        return $this->passthru('union', func_get_args());
898
    }
899
 
900
    /**
901
     * Create a new collection consisting of every n-th element.
902
     *
903
     * @param  int  $step
904
     * @param  int  $offset
905
     * @return static
906
     */
907
    public function nth($step, $offset = 0)
908
    {
909
        return new static(function () use ($step, $offset) {
910
            $position = 0;
911
 
912
            foreach ($this->slice($offset) as $item) {
913
                if ($position % $step === 0) {
914
                    yield $item;
915
                }
916
 
917
                $position++;
918
            }
919
        });
920
    }
921
 
922
    /**
923
     * Get the items with the specified keys.
924
     *
925
     * @param  \Illuminate\Support\Enumerable<array-key, TKey>|array<array-key, TKey>|string  $keys
926
     * @return static
927
     */
928
    public function only($keys)
929
    {
930
        if ($keys instanceof Enumerable) {
931
            $keys = $keys->all();
932
        } elseif (! is_null($keys)) {
933
            $keys = is_array($keys) ? $keys : func_get_args();
934
        }
935
 
936
        return new static(function () use ($keys) {
937
            if (is_null($keys)) {
938
                yield from $this;
939
            } else {
940
                $keys = array_flip($keys);
941
 
942
                foreach ($this as $key => $value) {
943
                    if (array_key_exists($key, $keys)) {
944
                        yield $key => $value;
945
 
946
                        unset($keys[$key]);
947
 
948
                        if (empty($keys)) {
949
                            break;
950
                        }
951
                    }
952
                }
953
            }
954
        });
955
    }
956
 
957
    /**
958
     * Push all of the given items onto the collection.
959
     *
960
     * @param  iterable<array-key, TValue>  $source
961
     * @return static
962
     */
963
    public function concat($source)
964
    {
965
        return (new static(function () use ($source) {
966
            yield from $this;
967
            yield from $source;
968
        }))->values();
969
    }
970
 
971
    /**
972
     * Get one or a specified number of items randomly from the collection.
973
     *
974
     * @param  int|null  $number
975
     * @return static<int, TValue>|TValue
976
     *
977
     * @throws \InvalidArgumentException
978
     */
979
    public function random($number = null)
980
    {
981
        $result = $this->collect()->random(...func_get_args());
982
 
983
        return is_null($number) ? $result : new static($result);
984
    }
985
 
986
    /**
987
     * Replace the collection items with the given items.
988
     *
989
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
990
     * @return static
991
     */
992
    public function replace($items)
993
    {
994
        return new static(function () use ($items) {
995
            $items = $this->getArrayableItems($items);
996
 
997
            foreach ($this as $key => $value) {
998
                if (array_key_exists($key, $items)) {
999
                    yield $key => $items[$key];
1000
 
1001
                    unset($items[$key]);
1002
                } else {
1003
                    yield $key => $value;
1004
                }
1005
            }
1006
 
1007
            foreach ($items as $key => $value) {
1008
                yield $key => $value;
1009
            }
1010
        });
1011
    }
1012
 
1013
    /**
1014
     * Recursively replace the collection items with the given items.
1015
     *
1016
     * @param  \Illuminate\Contracts\Support\Arrayable<TKey, TValue>|iterable<TKey, TValue>  $items
1017
     * @return static
1018
     */
1019
    public function replaceRecursive($items)
1020
    {
1021
        return $this->passthru('replaceRecursive', func_get_args());
1022
    }
1023
 
1024
    /**
1025
     * Reverse items order.
1026
     *
1027
     * @return static
1028
     */
1029
    public function reverse()
1030
    {
1031
        return $this->passthru('reverse', func_get_args());
1032
    }
1033
 
1034
    /**
1035
     * Search the collection for a given value and return the corresponding key if successful.
1036
     *
1037
     * @param  TValue|(callable(TValue,TKey): bool)  $value
1038
     * @param  bool  $strict
1039
     * @return TKey|bool
1040
     */
1041
    public function search($value, $strict = false)
1042
    {
1043
        /** @var (callable(TValue,TKey): bool) $predicate */
1044
        $predicate = $this->useAsCallable($value)
1045
            ? $value
1046
            : function ($item) use ($value, $strict) {
1047
                return $strict ? $item === $value : $item == $value;
1048
            };
1049
 
1050
        foreach ($this as $key => $item) {
1051
            if ($predicate($item, $key)) {
1052
                return $key;
1053
            }
1054
        }
1055
 
1056
        return false;
1057
    }
1058
 
1059
    /**
1060
     * Shuffle the items in the collection.
1061
     *
1062
     * @param  int|null  $seed
1063
     * @return static
1064
     */
1065
    public function shuffle($seed = null)
1066
    {
1067
        return $this->passthru('shuffle', func_get_args());
1068
    }
1069
 
1070
    /**
1071
     * Create chunks representing a "sliding window" view of the items in the collection.
1072
     *
1073
     * @param  int  $size
1074
     * @param  int  $step
1075
     * @return static<int, static>
1076
     */
1077
    public function sliding($size = 2, $step = 1)
1078
    {
1079
        return new static(function () use ($size, $step) {
1080
            $iterator = $this->getIterator();
1081
 
1082
            $chunk = [];
1083
 
1084
            while ($iterator->valid()) {
1085
                $chunk[$iterator->key()] = $iterator->current();
1086
 
1087
                if (count($chunk) == $size) {
1088
                    yield (new static($chunk))->tap(function () use (&$chunk, $step) {
1089
                        $chunk = array_slice($chunk, $step, null, true);
1090
                    });
1091
 
1092
                    // If the $step between chunks is bigger than each chunk's $size
1093
                    // we will skip the extra items (which should never be in any
1094
                    // chunk) before we continue to the next chunk in the loop.
1095
                    if ($step > $size) {
1096
                        $skip = $step - $size;
1097
 
1098
                        for ($i = 0; $i < $skip && $iterator->valid(); $i++) {
1099
                            $iterator->next();
1100
                        }
1101
                    }
1102
                }
1103
 
1104
                $iterator->next();
1105
            }
1106
        });
1107
    }
1108
 
1109
    /**
1110
     * Skip the first {$count} items.
1111
     *
1112
     * @param  int  $count
1113
     * @return static
1114
     */
1115
    public function skip($count)
1116
    {
1117
        return new static(function () use ($count) {
1118
            $iterator = $this->getIterator();
1119
 
1120
            while ($iterator->valid() && $count--) {
1121
                $iterator->next();
1122
            }
1123
 
1124
            while ($iterator->valid()) {
1125
                yield $iterator->key() => $iterator->current();
1126
 
1127
                $iterator->next();
1128
            }
1129
        });
1130
    }
1131
 
1132
    /**
1133
     * Skip items in the collection until the given condition is met.
1134
     *
1135
     * @param  TValue|callable(TValue,TKey): bool  $value
1136
     * @return static
1137
     */
1138
    public function skipUntil($value)
1139
    {
1140
        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);
1141
 
1142
        return $this->skipWhile($this->negate($callback));
1143
    }
1144
 
1145
    /**
1146
     * Skip items in the collection while the given condition is met.
1147
     *
1148
     * @param  TValue|callable(TValue,TKey): bool  $value
1149
     * @return static
1150
     */
1151
    public function skipWhile($value)
1152
    {
1153
        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);
1154
 
1155
        return new static(function () use ($callback) {
1156
            $iterator = $this->getIterator();
1157
 
1158
            while ($iterator->valid() && $callback($iterator->current(), $iterator->key())) {
1159
                $iterator->next();
1160
            }
1161
 
1162
            while ($iterator->valid()) {
1163
                yield $iterator->key() => $iterator->current();
1164
 
1165
                $iterator->next();
1166
            }
1167
        });
1168
    }
1169
 
1170
    /**
1171
     * Get a slice of items from the enumerable.
1172
     *
1173
     * @param  int  $offset
1174
     * @param  int|null  $length
1175
     * @return static
1176
     */
1177
    public function slice($offset, $length = null)
1178
    {
1179
        if ($offset < 0 || $length < 0) {
1180
            return $this->passthru('slice', func_get_args());
1181
        }
1182
 
1183
        $instance = $this->skip($offset);
1184
 
1185
        return is_null($length) ? $instance : $instance->take($length);
1186
    }
1187
 
1188
    /**
1189
     * Split a collection into a certain number of groups.
1190
     *
1191
     * @param  int  $numberOfGroups
1192
     * @return static<int, static>
1193
     */
1194
    public function split($numberOfGroups)
1195
    {
1196
        return $this->passthru('split', func_get_args());
1197
    }
1198
 
1199
    /**
1200
     * Get the first item in the collection, but only if exactly one item exists. Otherwise, throw an exception.
1201
     *
1202
     * @param  (callable(TValue, TKey): bool)|string  $key
1203
     * @param  mixed  $operator
1204
     * @param  mixed  $value
1205
     * @return TValue
1206
     *
1207
     * @throws \Illuminate\Support\ItemNotFoundException
1208
     * @throws \Illuminate\Support\MultipleItemsFoundException
1209
     */
1210
    public function sole($key = null, $operator = null, $value = null)
1211
    {
1212
        $filter = func_num_args() > 1
1213
            ? $this->operatorForWhere(...func_get_args())
1214
            : $key;
1215
 
1216
        return $this
1217
            ->unless($filter == null)
1218
            ->filter($filter)
1219
            ->take(2)
1220
            ->collect()
1221
            ->sole();
1222
    }
1223
 
1224
    /**
1225
     * Get the first item in the collection but throw an exception if no matching items exist.
1226
     *
1227
     * @param  (callable(TValue, TKey): bool)|string  $key
1228
     * @param  mixed  $operator
1229
     * @param  mixed  $value
1230
     * @return TValue
1231
     *
1232
     * @throws \Illuminate\Support\ItemNotFoundException
1233
     */
1234
    public function firstOrFail($key = null, $operator = null, $value = null)
1235
    {
1236
        $filter = func_num_args() > 1
1237
            ? $this->operatorForWhere(...func_get_args())
1238
            : $key;
1239
 
1240
        return $this
1241
            ->unless($filter == null)
1242
            ->filter($filter)
1243
            ->take(1)
1244
            ->collect()
1245
            ->firstOrFail();
1246
    }
1247
 
1248
    /**
1249
     * Chunk the collection into chunks of the given size.
1250
     *
1251
     * @param  int  $size
1252
     * @return static<int, static>
1253
     */
1254
    public function chunk($size)
1255
    {
1256
        if ($size <= 0) {
1257
            return static::empty();
1258
        }
1259
 
1260
        return new static(function () use ($size) {
1261
            $iterator = $this->getIterator();
1262
 
1263
            while ($iterator->valid()) {
1264
                $chunk = [];
1265
 
1266
                while (true) {
1267
                    $chunk[$iterator->key()] = $iterator->current();
1268
 
1269
                    if (count($chunk) < $size) {
1270
                        $iterator->next();
1271
 
1272
                        if (! $iterator->valid()) {
1273
                            break;
1274
                        }
1275
                    } else {
1276
                        break;
1277
                    }
1278
                }
1279
 
1280
                yield new static($chunk);
1281
 
1282
                $iterator->next();
1283
            }
1284
        });
1285
    }
1286
 
1287
    /**
1288
     * Split a collection into a certain number of groups, and fill the first groups completely.
1289
     *
1290
     * @param  int  $numberOfGroups
1291
     * @return static<int, static>
1292
     */
1293
    public function splitIn($numberOfGroups)
1294
    {
1295
        return $this->chunk(ceil($this->count() / $numberOfGroups));
1296
    }
1297
 
1298
    /**
1299
     * Chunk the collection into chunks with a callback.
1300
     *
1301
     * @param  callable(TValue, TKey, Collection<TKey, TValue>): bool  $callback
1302
     * @return static<int, static<int, TValue>>
1303
     */
1304
    public function chunkWhile(callable $callback)
1305
    {
1306
        return new static(function () use ($callback) {
1307
            $iterator = $this->getIterator();
1308
 
1309
            $chunk = new Collection;
1310
 
1311
            if ($iterator->valid()) {
1312
                $chunk[$iterator->key()] = $iterator->current();
1313
 
1314
                $iterator->next();
1315
            }
1316
 
1317
            while ($iterator->valid()) {
1318
                if (! $callback($iterator->current(), $iterator->key(), $chunk)) {
1319
                    yield new static($chunk);
1320
 
1321
                    $chunk = new Collection;
1322
                }
1323
 
1324
                $chunk[$iterator->key()] = $iterator->current();
1325
 
1326
                $iterator->next();
1327
            }
1328
 
1329
            if ($chunk->isNotEmpty()) {
1330
                yield new static($chunk);
1331
            }
1332
        });
1333
    }
1334
 
1335
    /**
1336
     * Sort through each item with a callback.
1337
     *
1338
     * @param  (callable(TValue, TValue): int)|null|int  $callback
1339
     * @return static
1340
     */
1341
    public function sort($callback = null)
1342
    {
1343
        return $this->passthru('sort', func_get_args());
1344
    }
1345
 
1346
    /**
1347
     * Sort items in descending order.
1348
     *
1349
     * @param  int  $options
1350
     * @return static
1351
     */
1352
    public function sortDesc($options = SORT_REGULAR)
1353
    {
1354
        return $this->passthru('sortDesc', func_get_args());
1355
    }
1356
 
1357
    /**
1358
     * Sort the collection using the given callback.
1359
     *
1360
     * @param  array<array-key, (callable(TValue, TValue): mixed)|(callable(TValue, TKey): mixed)|string|array{string, string}>|(callable(TValue, TKey): mixed)|string  $callback
1361
     * @param  int  $options
1362
     * @param  bool  $descending
1363
     * @return static
1364
     */
1365
    public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
1366
    {
1367
        return $this->passthru('sortBy', func_get_args());
1368
    }
1369
 
1370
    /**
1371
     * Sort the collection in descending order 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
     * @return static
1376
     */
1377
    public function sortByDesc($callback, $options = SORT_REGULAR)
1378
    {
1379
        return $this->passthru('sortByDesc', func_get_args());
1380
    }
1381
 
1382
    /**
1383
     * Sort the collection keys.
1384
     *
1385
     * @param  int  $options
1386
     * @param  bool  $descending
1387
     * @return static
1388
     */
1389
    public function sortKeys($options = SORT_REGULAR, $descending = false)
1390
    {
1391
        return $this->passthru('sortKeys', func_get_args());
1392
    }
1393
 
1394
    /**
1395
     * Sort the collection keys in descending order.
1396
     *
1397
     * @param  int  $options
1398
     * @return static
1399
     */
1400
    public function sortKeysDesc($options = SORT_REGULAR)
1401
    {
1402
        return $this->passthru('sortKeysDesc', func_get_args());
1403
    }
1404
 
1405
    /**
1406
     * Sort the collection keys using a callback.
1407
     *
1408
     * @param  callable(TKey, TKey): int  $callback
1409
     * @return static
1410
     */
1411
    public function sortKeysUsing(callable $callback)
1412
    {
1413
        return $this->passthru('sortKeysUsing', func_get_args());
1414
    }
1415
 
1416
    /**
1417
     * Take the first or last {$limit} items.
1418
     *
1419
     * @param  int  $limit
1420
     * @return static
1421
     */
1422
    public function take($limit)
1423
    {
1424
        if ($limit < 0) {
1425
            return $this->passthru('take', func_get_args());
1426
        }
1427
 
1428
        return new static(function () use ($limit) {
1429
            $iterator = $this->getIterator();
1430
 
1431
            while ($limit--) {
1432
                if (! $iterator->valid()) {
1433
                    break;
1434
                }
1435
 
1436
                yield $iterator->key() => $iterator->current();
1437
 
1438
                if ($limit) {
1439
                    $iterator->next();
1440
                }
1441
            }
1442
        });
1443
    }
1444
 
1445
    /**
1446
     * Take items in the collection until the given condition is met.
1447
     *
1448
     * @param  TValue|callable(TValue,TKey): bool  $value
1449
     * @return static
1450
     */
1451
    public function takeUntil($value)
1452
    {
1453
        /** @var callable(TValue, TKey): bool $callback */
1454
        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);
1455
 
1456
        return new static(function () use ($callback) {
1457
            foreach ($this as $key => $item) {
1458
                if ($callback($item, $key)) {
1459
                    break;
1460
                }
1461
 
1462
                yield $key => $item;
1463
            }
1464
        });
1465
    }
1466
 
1467
    /**
1468
     * Take items in the collection until a given point in time.
1469
     *
1470
     * @param  \DateTimeInterface  $timeout
1471
     * @return static
1472
     */
1473
    public function takeUntilTimeout(DateTimeInterface $timeout)
1474
    {
1475
        $timeout = $timeout->getTimestamp();
1476
 
1477
        return new static(function () use ($timeout) {
1478
            if ($this->now() >= $timeout) {
1479
                return;
1480
            }
1481
 
1482
            foreach ($this as $key => $value) {
1483
                yield $key => $value;
1484
 
1485
                if ($this->now() >= $timeout) {
1486
                    break;
1487
                }
1488
            }
1489
        });
1490
    }
1491
 
1492
    /**
1493
     * Take items in the collection while the given condition is met.
1494
     *
1495
     * @param  TValue|callable(TValue,TKey): bool  $value
1496
     * @return static
1497
     */
1498
    public function takeWhile($value)
1499
    {
1500
        /** @var callable(TValue, TKey): bool $callback */
1501
        $callback = $this->useAsCallable($value) ? $value : $this->equality($value);
1502
 
1503
        return $this->takeUntil(function ($item, $key) use ($callback) {
1504
            return ! $callback($item, $key);
1505
        });
1506
    }
1507
 
1508
    /**
1509
     * Pass each item in the collection to the given callback, lazily.
1510
     *
1511
     * @param  callable(TValue, TKey): mixed  $callback
1512
     * @return static
1513
     */
1514
    public function tapEach(callable $callback)
1515
    {
1516
        return new static(function () use ($callback) {
1517
            foreach ($this as $key => $value) {
1518
                $callback($value, $key);
1519
 
1520
                yield $key => $value;
1521
            }
1522
        });
1523
    }
1524
 
1525
    /**
1526
     * Convert a flatten "dot" notation array into an expanded array.
1527
     *
1528
     * @return static
1529
     */
1530
    public function undot()
1531
    {
1532
        return $this->passthru('undot', []);
1533
    }
1534
 
1535
    /**
1536
     * Return only unique items from the collection array.
1537
     *
1538
     * @param  (callable(TValue, TKey): mixed)|string|null  $key
1539
     * @param  bool  $strict
1540
     * @return static
1541
     */
1542
    public function unique($key = null, $strict = false)
1543
    {
1544
        $callback = $this->valueRetriever($key);
1545
 
1546
        return new static(function () use ($callback, $strict) {
1547
            $exists = [];
1548
 
1549
            foreach ($this as $key => $item) {
1550
                if (! in_array($id = $callback($item, $key), $exists, $strict)) {
1551
                    yield $key => $item;
1552
 
1553
                    $exists[] = $id;
1554
                }
1555
            }
1556
        });
1557
    }
1558
 
1559
    /**
1560
     * Reset the keys on the underlying array.
1561
     *
1562
     * @return static<int, TValue>
1563
     */
1564
    public function values()
1565
    {
1566
        return new static(function () {
1567
            foreach ($this as $item) {
1568
                yield $item;
1569
            }
1570
        });
1571
    }
1572
 
1573
    /**
1574
     * Zip the collection together with one or more arrays.
1575
     *
1576
     * e.g. new LazyCollection([1, 2, 3])->zip([4, 5, 6]);
1577
     *      => [[1, 4], [2, 5], [3, 6]]
1578
     *
1579
     * @template TZipValue
1580
     *
1581
     * @param  \Illuminate\Contracts\Support\Arrayable<array-key, TZipValue>|iterable<array-key, TZipValue>  ...$items
1582
     * @return static<int, static<int, TValue|TZipValue>>
1583
     */
1584
    public function zip($items)
1585
    {
1586
        $iterables = func_get_args();
1587
 
1588
        return new static(function () use ($iterables) {
1589
            $iterators = Collection::make($iterables)->map(function ($iterable) {
1590
                return $this->makeIterator($iterable);
1591
            })->prepend($this->getIterator());
1592
 
1593
            while ($iterators->contains->valid()) {
1594
                yield new static($iterators->map->current());
1595
 
1596
                $iterators->each->next();
1597
            }
1598
        });
1599
    }
1600
 
1601
    /**
1602
     * Pad collection to the specified length with a value.
1603
     *
1604
     * @template TPadValue
1605
     *
1606
     * @param  int  $size
1607
     * @param  TPadValue  $value
1608
     * @return static<int, TValue|TPadValue>
1609
     */
1610
    public function pad($size, $value)
1611
    {
1612
        if ($size < 0) {
1613
            return $this->passthru('pad', func_get_args());
1614
        }
1615
 
1616
        return new static(function () use ($size, $value) {
1617
            $yielded = 0;
1618
 
1619
            foreach ($this as $index => $item) {
1620
                yield $index => $item;
1621
 
1622
                $yielded++;
1623
            }
1624
 
1625
            while ($yielded++ < $size) {
1626
                yield $value;
1627
            }
1628
        });
1629
    }
1630
 
1631
    /**
1632
     * Get the values iterator.
1633
     *
1634
     * @return \Traversable<TKey, TValue>
1635
     */
1636
    public function getIterator(): Traversable
1637
    {
1638
        return $this->makeIterator($this->source);
1639
    }
1640
 
1641
    /**
1642
     * Count the number of items in the collection.
1643
     *
1644
     * @return int
1645
     */
1646
    public function count(): int
1647
    {
1648
        if (is_array($this->source)) {
1649
            return count($this->source);
1650
        }
1651
 
1652
        return iterator_count($this->getIterator());
1653
    }
1654
 
1655
    /**
1656
     * Make an iterator from the given source.
1657
     *
1658
     * @template TIteratorKey of array-key
1659
     * @template TIteratorValue
1660
     *
1661
     * @param  \IteratorAggregate<TIteratorKey, TIteratorValue>|array<TIteratorKey, TIteratorValue>|(callable(): \Generator<TIteratorKey, TIteratorValue>)  $source
1662
     * @return \Traversable<TIteratorKey, TIteratorValue>
1663
     */
1664
    protected function makeIterator($source)
1665
    {
1666
        if ($source instanceof IteratorAggregate) {
1667
            return $source->getIterator();
1668
        }
1669
 
1670
        if (is_array($source)) {
1671
            return new ArrayIterator($source);
1672
        }
1673
 
399 lars 1674
        if (is_callable($source)) {
1675
            $maybeTraversable = $source();
1676
 
1677
            return $maybeTraversable instanceof Traversable
1678
                ? $maybeTraversable
1679
                : new ArrayIterator(Arr::wrap($maybeTraversable));
1680
        }
1681
 
1682
        return new ArrayIterator((array) $source);
148 lars 1683
    }
1684
 
1685
    /**
1686
     * Explode the "value" and "key" arguments passed to "pluck".
1687
     *
1688
     * @param  string|string[]  $value
1689
     * @param  string|string[]|null  $key
1690
     * @return array{string[],string[]|null}
1691
     */
1692
    protected function explodePluckParameters($value, $key)
1693
    {
1694
        $value = is_string($value) ? explode('.', $value) : $value;
1695
 
1696
        $key = is_null($key) || is_array($key) ? $key : explode('.', $key);
1697
 
1698
        return [$value, $key];
1699
    }
1700
 
1701
    /**
1702
     * Pass this lazy collection through a method on the collection class.
1703
     *
1704
     * @param  string  $method
1705
     * @param  array<mixed>  $params
1706
     * @return static
1707
     */
1708
    protected function passthru($method, array $params)
1709
    {
1710
        return new static(function () use ($method, $params) {
1711
            yield from $this->collect()->$method(...$params);
1712
        });
1713
    }
1714
 
1715
    /**
1716
     * Get the current time.
1717
     *
1718
     * @return int
1719
     */
1720
    protected function now()
1721
    {
1722
        return time();
1723
    }
1724
}