GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 9bd2f0...277002 )
by Dušan
03:03
created

collection_functions.php ➔ DusanKasan\Knapsack\second()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 1
cts 1
cp 1
crap 1
rs 10
1
<?php
2
3
namespace DusanKasan\Knapsack;
4
5
use ArrayIterator;
6
use DusanKasan\Knapsack\Exceptions\InvalidArgument;
7
use DusanKasan\Knapsack\Exceptions\ItemNotFound;
8
use DusanKasan\Knapsack\Exceptions\NoMoreItems;
9
use IteratorAggregate;
10
use Traversable;
11
12
/**
13
     * Converts $collection to array. If there are multiple items with the same key, only the last will be preserved.
14
 *
15
 * @param array|Traversable $collection
16
 * @return array
17
 */
18
function toArray($collection)
19
{
20 61
    $arr = [];
21 61
    foreach ($collection as $key => $value) {
22 61
        $arr[$key] = $value;
23 61
    }
24
25 61
    return $arr;
26
}
27
28
/**
29
 * Returns a lazy collection of distinct items in $collection.
30
 *
31
 * @param array|Traversable $collection
32
 * @return Collection
33
 */
34
function distinct($collection)
35
{
36
    $generatorFactory = function () use ($collection) {
37 1
        $distinctValues = [];
38
39 1
        foreach ($collection as $key => $value) {
40 1
            if (!in_array($value, $distinctValues)) {
41 1
                $distinctValues[] = $value;
42 1
                yield $key => $value;
43 1
            }
44 1
        }
45 1
    };
46
47 1
    return new Collection($generatorFactory);
48
}
49
50
/**
51
 * Returns number of items in $collection.
52
 *
53
 * @param array|Traversable $collection
54
 * @return int
55
 */
56
function size($collection)
57
{
58 8
    $result = 0;
59 8
    foreach ($collection as $value) {
60 8
        $result++;
61 8
    }
62
63 8
    return $result;
64
}
65
66
/**
67
 * Returns a non-lazy collection with items from $collection in reversed order.
68
 *
69
 * @param array|Traversable $collection
70
 * @return Collection
71
 */
72
function reverse($collection)
73
{
74
    $generatorFactory = function () use ($collection) {
75 4
        $array = [];
76 4
        foreach ($collection as $key => $value) {
77 3
            $array[] = [$key, $value];
78 4
        }
79
80 4
        return map(
81 5
            indexBy(
82 4
                array_reverse($array),
83
                function($item) {
84 3
                    return $item[0];
85
                }
86 4
            ),
87
            function($item) {
88 3
                return $item[1];
89
            }
90 4
        );
91 4
    };
92
93 4
    return new Collection($generatorFactory);
94
}
95
96
/**
97
 * Returns a lazy collection of values from $collection (i.e. the keys are reset).
98
 *
99
 * @param array|Traversable $collection
100
 * @return Collection
101
 */
102
function values($collection)
103
{
104
    $generatorFactory = function () use ($collection) {
105 30
        foreach ($collection as $value) {
106 27
            yield $value;
107 23
        }
108 30
    };
109
110 30
    return new Collection($generatorFactory);
111
}
112
113
/**
114
 * Returns a lazy collection of keys from $collection.
115
 *
116
 * @param array|Traversable $collection
117
 * @return Collection
118
 */
119
function keys($collection)
120
{
121
    $generatorFactory = function () use ($collection) {
122 1
        foreach ($collection as $key => $value) {
123 1
            yield $key;
124 1
        }
125 1
    };
126
127 1
    return new Collection($generatorFactory);
128
}
129
130
/**
131
 * Returns a lazy collection of items from $collection repeated infinitely.
132
 *
133
 * @param array|Traversable $collection
134
 * @return Collection
135
 */
136
function cycle($collection)
137
{
138
    $generatorFactory = function () use ($collection) {
139 1
        while (true) {
140 1
            foreach ($collection as $key => $value) {
141 1
                yield $key => $value;
142 1
            }
143 1
        }
144 1
    };
145
146 1
    return new Collection($generatorFactory);
147
}
148
149
/**
150
 * Returns a non-lazy collection of shuffled items from $collection.
151
 *
152
 * @param array|Traversable $collection
153
 * @return Collection
154
 */
155
function shuffle($collection)
156
{
157 1
    $buffer = [];
158 1
    foreach ($collection as $key => $value) {
159 1
        $buffer[] = [$key, $value];
160 1
    }
161
162 1
    \shuffle($buffer);
163
164 1
    return dereferenceKeyValue($buffer);
165
}
166
167
/**
168
 * Returns true if $collection does not contain any items.
169
 *
170
 * @param array|Traversable $collection
171
 * @return bool
172
 */
173
function isEmpty($collection)
174
{
175 2
    foreach ($collection as $value) {
176 1
        return false;
177 1
    }
178
179 1
    return true;
180
}
181
182
/**
183
 * Returns true if $collection does contain any items.
184
 *
185
 * @param array|Traversable $collection
186
 * @return bool
187
 */
188
function isNotEmpty($collection)
189
{
190 2
    return !isEmpty($collection);
191
}
192
193
/**
194
 * Returns a collection where keys are distinct values from $collection and values are number of occurrences of each
195
 * value.
196
 *
197
 * @param array|Traversable $collection
198
 * @return Collection
199
 */
200
function frequencies($collection)
201
{
202 1
    return countBy($collection, '\DusanKasan\Knapsack\identity');
203
}
204
205
/**
206
 * Returns the first item of $collection or throws ItemNotFound if #collection is empty.
207
 *
208
 * @param array|Traversable $collection
209
 * @return mixed
210
 */
211
function first($collection)
212
{
213 15
    return getNth($collection, 0);
214
}
215
216
/**
217
 * Returns the last item of $collection or throws ItemNotFound if #collection is empty.
218
 *
219
 * @param array|Traversable $collection
220
 * @return mixed
221
 */
222
function last($collection)
223
{
224 2
    return first(reverse($collection));
225
}
226
227
/**
228
 * Returns a lazy collection of items of $collection where value of each item is set to the return value of calling
229
 * $function on its value and key.
230
 *
231
 * @param array|Traversable $collection
232
 * @param callable $function ($value, $key)
233
 * @return Collection
234
 */
235 View Code Duplication
function map($collection, callable $function)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
{
237
    $generatorFactory = function () use ($collection, $function) {
238 13
        foreach ($collection as $key => $value) {
239 12
            yield $key => $function($value, $key);
240 12
        }
241 13
    };
242
243 13
    return new Collection($generatorFactory);
244
}
245
246
/**
247
 * Returns a lazy collection of items from $collection for which $function returns true.
248
 *
249
 * @param array|Traversable $collection
250
 * @param callable $function ($value, $key)
251
 * @return Collection
252
 */
253 View Code Duplication
function filter($collection, callable $function)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
254
{
255
    $generatorFactory = function () use ($collection, $function) {
256 6
        foreach ($collection as $key => $value) {
257 6
            if ($function($value, $key)) {
258 5
                yield $key => $value;
259 5
            }
260 6
        }
261 6
    };
262
263 6
    return new Collection($generatorFactory);
264
}
265
266
/**
267
 * Returns a lazy collection with items from all $collections passed as argument appended together
268
 *
269
 * @param array|Traversable ...$collections
270
 * @return Collection
271
 */
272
function concat(...$collections)
273
{
274
    $generatorFactory = function () use ($collections) {
275 3
        foreach ($collections as $collection) {
276 3
            foreach ($collection as $key => $value) {
277 3
                yield $key => $value;
278 3
            }
279 3
        }
280 3
    };
281
282 3
    return new Collection($generatorFactory);
283
}
284
285
/**
286
 * Reduces the collection to single value by iterating over the collection and calling $reduction while
287
 * passing $startValue and current key/item as parameters. The output of $function is used as $startValue in
288
 * next iteration. The output of $function on last element is the return value of this function.
289
 *
290
 * @param array|Traversable $collection
291
 * @param callable $function ($value, $key)
292
 * @param mixed $startValue
293
 * @return mixed
294
 */
295
function reduce($collection, callable $function, $startValue)
296
{
297 3
    $tmp = duplicate($startValue);
298
299 3
    foreach ($collection as $key => $value) {
300 3
        $tmp = $function($tmp, $value, $key);
301 3
    }
302
303 3
    return $tmp;
304
}
305
306
/**
307
 * Flattens multiple levels of nesting in collection. If $levelsToFlatten is not specified, flattens all levels of
308
 * nesting.
309
 *
310
 * @param array|Traversable $collection
311
 * @param int $levelsToFlatten -1 to flatten everything
312
 * @return Collection
313
 */
314
function flatten($collection, $levelsToFlatten = -1)
315
{
316
    $generatorFactory = function () use ($collection, $levelsToFlatten) {
317 3
        $flattenNextLevel = $levelsToFlatten < 0 || $levelsToFlatten > 0;
318 3
        $childLevelsToFlatten = $levelsToFlatten > 0 ? $levelsToFlatten - 1 : $levelsToFlatten;
319
320 3
        foreach ($collection as $key => $value) {
321 3
            if ($flattenNextLevel && (is_array($value) || $value instanceof Traversable)) {
322 3
                foreach (flatten($value, $childLevelsToFlatten) as $childKey => $childValue) {
323 3
                    yield $childKey => $childValue;
324 3
                }
325 3
            } else {
326 3
                yield $key => $value;
327
            }
328 3
        }
329 3
    };
330
331 3
    return new Collection($generatorFactory);
332
}
333
334
/**
335
 * Returns a non-lazy collection sorted using $collection($item1, $item2, $key1, $key2 ). $collection should
336
 * return true if first item is larger than the second and false otherwise.
337
 *
338
 * @param array|Traversable $collection
339
 * @param callable $function ($value1, $value2, $key1, $key2)
340
 * @return Collection
341
 */
342
function sort($collection, callable $function)
343
{
344 1
    $array = iterator_to_array(
345 1
        values(
346 1
            map(
347 1
                $collection,
348
                function ($value, $key) {
349 1
                    return [$key, $value];
350
                }
351 1
            )
352 1
        )
353 1
    );
354
355 1
    uasort(
356 1
        $array,
357
        function ($a, $b) use ($function) {
358 1
            return $function($a[1], $b[1], $a[0], $b[0]);
359
        }
360 1
    );
361
362 1
    return dereferenceKeyValue($array);
363
}
364
365
/**
366
 * Returns a lazy collection that is a part of $collection starting from $from position and ending in $to position.
367
 * If $to is not provided, the returned collection is contains all items from $from until end of $collection. All items
368
 * before $from are iterated over, but not included in result.
369
 *
370
 * @param array|Traversable $collection
371
 * @param int $from
372
 * @param int $to -1 to slice until end
373
 * @return Collection
374
 */
375
function slice($collection, $from, $to = -1)
376
{
377
    $generatorFactory = function () use ($collection, $from, $to) {
378 17
        $index = 0;
379 17
        foreach ($collection as $key => $value) {
380 17
            if ($index >= $from && ($index < $to || $to == -1)) {
381 16
                yield $key => $value;
382 17
            } elseif ($index >= $to && $to >= 0) {
383 12
                break;
384
            }
385
386 17
            $index++;
387 17
        }
388 17
    };
389
390 17
    return new Collection($generatorFactory);
391
}
392
393
/**
394
 * Returns a non-lazy collection of items grouped by the result of $function.
395
 *
396
 * @param array|Traversable $collection
397
 * @param callable $function ($value, $key)
398
 * @return Collection
399
 */
400
function groupBy($collection, callable $function)
401
{
402 4
    $result = [];
403
404 4
    foreach ($collection as $key => $value) {
405 4
        $newKey = $function($value, $key);
406
407 4
        $group = isset($result[$newKey]) ? $result[$newKey] : new Collection([]);
408 4
        $result[$newKey] = $group->append($value);
409 4
    }
410
411 4
    return Collection::from($result);
412
}
413
414
415
/**
416
 * Returns a non-lazy collection of items grouped by the value at given key. Ignores non-collection items and items
417
 * without the given keys
418
 *
419
 * @param array|Traversable $collection
420
 * @param mixed $key
421
 * @return Collection
422
 */
423
function groupByKey($collection, $key)
424
{
425
    $generatorFactory = function () use ($collection, $key) {
426
427 1
        return groupBy(
428 1
            filter(
429 1
                $collection,
430
                function ($item) use ($key) {
431 1
                    return isCollection($item) && has($item, $key);
432
                }
433 1
            ),
434
            function($value) use ($key) {
435 1
                return get($value, $key);
436
            }
437 1
        );
438 1
    };
439
440 1
    return new Collection($generatorFactory);
441
}
442
/**
443
 * Executes $function for each item in $collection
444
 *
445
 * @param array|Traversable $collection
446
 * @param callable $function ($value, $key)
447
 * @return Collection
448
 */
449 View Code Duplication
function each($collection, callable $function)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
450
{
451
    $generatorFactory = function () use ($collection, $function) {
452 1
        foreach ($collection as $key => $value) {
453 1
            $function($value, $key);
454
455 1
            yield $key => $value;
456 1
        }
457 1
    };
458
459 1
    return new Collection($generatorFactory);
460
}
461
462
/**
463
 * Returns an item with $key key from $collection. If that key is not present, throws ItemNotFound.
464
 *
465
 * @param array|Traversable $collection
466
 * @param mixed $key
467
 * @return mixed
468
 */
469
function get($collection, $key)
470
{
471 20
    foreach ($collection as $valueKey => $value) {
472 17
        if ($key === $valueKey) {
473 17
            return $value;
474
        }
475 15
    }
476
477 8
    throw new ItemNotFound;
478
}
479
480
/**
481
 * Returns an item with $key key from $collection. If that key is not present, returns $default.
482
 *
483
 * @param array|Traversable $collection
484
 * @param mixed $key
485
 * @param mixed $default value returned if key is not found
486
 * @return mixed
487
 */
488
function getOrDefault($collection, $key, $default)
489
{
490
    try {
491 2
        return get($collection, $key);
492 2
    } catch (ItemNotFound $e) {
493 2
        return $default;
494
    }
495
}
496
497
/**
498
 * Returns the first item from $collection for which $function returns true. If item like that is not present, returns
499
 * $default.
500
 *
501
 * @param array|Traversable $collection
502
 * @param callable $function ($value, $key)
503
 * @param mixed $default
504
 * @return mixed
505
 */
506
function find($collection, callable $function, $default = null)
507
{
508 1
    foreach ($collection as $key => $value) {
509 1
        if ($function($value, $key)) {
510 1
            return $value;
511
        }
512 1
    }
513
514 1
    return $default;
515
}
516
517
/**
518
 * Returns a lazy collection by changing keys of $collection for each item to the result of $function for
519
 * that item.
520
 *
521
 * @param array|Traversable $collection
522
 * @param callable $function ($value, $key)
523
 * @return Collection
524
 */
525 View Code Duplication
function indexBy($collection, callable $function)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
526
{
527
    $generatorFactory = function () use ($collection, $function) {
528 5
        foreach ($collection as $key => $value) {
529 4
            yield $function($value, $key) => $value;
530 4
        }
531 5
    };
532
533 5
    return new Collection($generatorFactory);
534
}
535
536
/**
537
 * Returns a non-lazy collection of items whose keys are the return values of $function and values are the number of
538
 * items in this collection for which the $function returned this value.
539
 *
540
 * @param array|Traversable $collection
541
 * @param callable $function ($value, $key)
542
 * @return Collection
543
 */
544
function countBy($collection, callable $function)
545
{
546 2
    return map(
547 2
        groupBy($collection, $function),
548
        '\DusanKasan\Knapsack\size'
549 2
    );
550
}
551
552
/**
553
 * Returns true if $function returns true for every item in $collection
554
 *
555
 * @param array|Traversable $collection
556
 * @param callable $function ($value, $key)
557
 * @return bool
558
 */
559
function every($collection, callable $function)
560
{
561 1
    foreach ($collection as $key => $value) {
562 1
        if (!$function($value, $key)) {
563 1
            return false;
564
        }
565 1
    }
566
567 1
    return true;
568
}
569
570
/**
571
 * Returns true if $function returns true for at least one item in $collection.
572
 *
573
 * @param array|Traversable $collection
574
 * @param callable $function ($value, $key)
575
 * @return bool
576
 */
577
function some($collection, callable $function)
578
{
579 1
    foreach ($collection as $key => $value) {
580 1
        if ($function($value, $key)) {
581 1
            return true;
582
        }
583 1
    }
584
585 1
    return false;
586
}
587
588
/**
589
 * Returns true if $needle is found in $collection values.
590
 *
591
 * @param $collection
592
 * @param mixed $needle
593
 * @return bool
594
 */
595
function contains($collection, $needle)
596
{
597 1
    foreach ($collection as $key => $value) {
598 1
        if ($value === $needle) {
599 1
            return true;
600
        }
601 1
    }
602
603 1
    return false;
604
}
605
606
/**
607
 * Reduce that walks from right to the left.
608
 *
609
 * @param array|Traversable $collection
610
 * @param callable $function
611
 * @param mixed $startValue
612
 * @return mixed
613
 */
614
function reduceRight($collection, callable $function, $startValue)
615
{
616 1
    return reduce(reverse($collection), $function, $startValue);
617
}
618
619
/**
620
 * Returns a lazy collection of first $numberOfItems items of $collection.
621
 *
622
 * @param array|Traversable $collection
623
 * @param int $numberOfItems
624
 * @return Collection
625
 */
626
function take($collection, $numberOfItems)
627
{
628 12
    return slice($collection, 0, $numberOfItems);
629
}
630
631
/**
632
 * Returns a lazy collection of all but first $numberOfItems items of $collection.
633
 *
634
 * @param array|Traversable $collection
635
 * @param int $numberOfItems
636
 * @return Collection
637
 */
638
function drop($collection, $numberOfItems)
639
{
640 6
    return slice($collection, $numberOfItems);
641
}
642
643
/**
644
 * Returns a lazy collection of values, where first value is $value and all subsequent values are computed by applying
645
 * $function to the last value in the collection. By default this produces an infinite collection. However you can
646
 * end the collection by throwing a NoMoreItems exception.
647
 *
648
 * @param mixed $value
649
 * @param callable $function ($value, $key)
650
 * @return Collection
651
 */
652
function iterate($value, callable $function)
653
{
654 4
    $duplicated = duplicate($value);
655
    $generatorFactory = function () use ($duplicated, $function) {
656 4
        $value = $duplicated;
657
658 4
        yield $value;
659
660 4
        while (true) {
661
            try {
662 4
                $value = $function($value);
663 4
                yield $value;
664 4
            } catch (NoMoreItems $e) {
665 2
                break;
666
            }
667 4
        }
668 4
    };
669
670 4
    return new Collection($generatorFactory);
671
}
672
673
/**
674
 * Returns a lazy collection of items from $collection for which $function returned true.
675
 *
676
 * @param array|Traversable $collection
677
 * @param callable $function ($value, $key)
678
 * @return Collection
679
 */
680
function reject($collection, callable $function)
681
{
682 2
    return filter(
683 2
        $collection,
684
        function($value, $key) use ($function) {
685 2
            return !$function($value, $key);
686
        }
687 2
    );
688
}
689
690
/**
691
 * Returns a lazy collection of items in $collection without the last $numberOfItems items.
692
 *
693
 * @param array|Traversable $collection
694
 * @param int $numberOfItems
695
 * @return Collection
696
 */
697
function dropLast($collection, $numberOfItems = 1)
698
{
699
    $generatorFactory = function () use ($collection, $numberOfItems) {
700 1
        $buffer = [];
701
702 1
        foreach ($collection as $key => $value) {
703 1
            $buffer[] = [$key, $value];
704
705 1
            if (count($buffer) > $numberOfItems) {
706 1
                $val = array_shift($buffer);
707 1
                yield $val[0] => $val[1];
708 1
            }
709 1
        }
710 1
    };
711
712 1
    return new Collection($generatorFactory);
713
}
714
715
/**
716
 * Returns a lazy collection of items from $collection separated by $separator.
717
 *
718
 * @param array|Traversable $collection
719
 * @param mixed $separator
720
 * @return Collection
721
 */
722
function interpose($collection, $separator)
723
{
724
    $generatorFactory = function () use ($collection, $separator) {
725 1
        foreach (take($collection, 1) as $key => $value) {
726 1
            yield $key => $value;
727 1
        }
728
729 1
        foreach (drop($collection, 1) as $key => $value) {
730 1
            yield $separator;
731 1
            yield $key => $value;
732 1
        }
733 1
    };
734
735 1
    return new Collection($generatorFactory);
736
}
737
738
/**
739
 * Returns a lazy collection of first item from first collection, first item from second, second from first and
740
 * so on. Accepts any number of collections.
741
 *
742
 * @param array|Traversable ...$collections
743
 * @return Collection
744
 */
745
function interleave(...$collections)
746
{
747
    $generatorFactory = function () use ($collections) {
748 1
        $normalizedCollection = array_map(
749
            function ($collection) {
750 1
                $traversable = new Collection($collection);
751 1
                $traversable->rewind();
752 1
                return $traversable;
753 1
            },
754
            $collections
755 1
        );
756
757
        do {
758 1
            $valid = false;
759 1
            foreach ($normalizedCollection as $collection) {
760 1
                if ($collection->valid()) {
761 1
                    yield $collection->key() => $collection->current();
762 1
                    $collection->next();
763 1
                    $valid = true;
764 1
                }
765 1
            }
766 1
        } while ($valid);
767 1
    };
768
769 1
    return new Collection($generatorFactory);
770
}
771
772
/**
773
 * Returns a lazy collection of items in $collection with $value added as first element. If $key is not provided
774
 * it will be next integer index.
775
 *
776
 * @param array|Traversable $collection
777
 * @param mixed $value
778
 * @param mixed|null $key
779
 * @return Collection
780
 */
781 View Code Duplication
function prepend($collection, $value, $key = null)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
782
{
783
    $generatorFactory = function () use ($collection, $value, $key) {
784 2
        if ($key === null) {
785 1
            yield $value;
786 1
        } else {
787 1
            yield $key => $value;
788
        }
789
790 2
        foreach ($collection as $key => $value) {
791 2
            yield $key => $value;
792 2
        }
793 2
    };
794
795 2
    return new Collection($generatorFactory);
796
}
797
798
/**
799
 * Returns a lazy collection of items in $collection with $value added as last element. If $key is not provided
800
 * it will be next integer index.
801
 *
802
 * @param array|Traversable $collection
803
 * @param mixed $value
804
 * @param mixed|null $key
805
 * @return Collection
806
 */
807 View Code Duplication
function append($collection, $value, $key = null)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
808
{
809
    $generatorFactory = function () use ($collection, $value, $key) {
810 9
        foreach ($collection as $k => $v) {
811 9
            yield $k => $v;
812 9
        }
813
814 9
        if ($key === null) {
815 7
            yield $value;
816 7
        } else {
817 2
            yield $key => $value;
818
        }
819 9
    };
820
821 9
    return new Collection($generatorFactory);
822
}
823
824
/**
825
 * Returns a lazy collection by removing items from $collection until first item for which $function returns false.
826
 *
827
 * @param array|Traversable $collection
828
 * @param callable $function ($value, $key)
829
 * @return Collection
830
 */
831 View Code Duplication
function dropWhile($collection, callable $function)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
832
{
833
    $generatorFactory = function () use ($collection, $function) {
834 2
        $shouldDrop = true;
835 2
        foreach ($collection as $key => $value) {
836 2
            if ($shouldDrop) {
837 2
                $shouldDrop = $function($value, $key);
838 2
            }
839
840 2
            if (!$shouldDrop) {
841 2
                yield $key => $value;
842 2
            }
843 2
        }
844 2
    };
845
846 2
    return new Collection($generatorFactory);
847
}
848
849
/**
850
 * Returns a lazy collection of items from $collection until first item for which $function returns false.
851
 *
852
 * @param array|Traversable $collection
853
 * @param callable $function ($value, $key)
854
 * @return Collection
855
 */
856 View Code Duplication
function takeWhile($collection, callable $function)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
857
{
858
    $generatorFactory = function () use ($collection, $function) {
859 2
        $shouldTake = true;
860 2
        foreach ($collection as $key => $value) {
861 2
            if ($shouldTake) {
862 2
                $shouldTake = $function($value, $key);
863 2
            }
864
865 2
            if ($shouldTake) {
866 2
                yield $key => $value;
867 2
            }
868 2
        }
869 2
    };
870
871 2
    return new Collection($generatorFactory);
872
}
873
874
/**
875
 * Returns a lazy collection. A result of calling map and flatten(1)
876
 *
877
 * @param array|Traversable $collection
878
 * @param callable $function ($value, $key)
879
 * @return Collection
880
 */
881
function mapcat($collection, callable $function)
882
{
883 1
    return flatten(map($collection, $function), 1);
884
}
885
886
/**
887
 * Returns a lazy collection [take($collection, $position), drop($collection, $position)]
888
 *
889
 * @param array|Traversable $collection
890
 * @param int $position
891
 * @return Collection
892
 */
893
function splitAt($collection, $position)
894
{
895
    $generatorFactory = function () use ($collection, $position) {
896 1
        yield take($collection, $position);
897 1
        yield drop($collection, $position);
898 1
    };
899
900 1
    return new Collection($generatorFactory);
901
}
902
903
/**
904
 * Returns a lazy collection [takeWhile($collection, $function), dropWhile($collection, $function)]
905
 *
906
 * @param array|Traversable $collection
907
 * @param callable $function ($value, $key)
908
 * @return Collection
909
 */
910
function splitWith($collection, callable $function)
911
{
912
    $generatorFactory = function () use ($collection, $function) {
913 1
        yield takeWhile($collection, $function);
914 1
        yield dropWhile($collection, $function);
915 1
    };
916
917 1
    return new Collection($generatorFactory);
918
}
919
920
/**
921
 * Returns a lazy collection with items from $collection but values that are found in keys of $replacementMap
922
 * are replaced by their values.
923
 *
924
 * @param array|Traversable $collection
925
 * @param array|Traversable $replacementMap
926
 * @return Collection
927
 */
928
function replace($collection, $replacementMap)
929
{
930
    $generatorFactory = function () use ($collection, $replacementMap) {
931 1
        foreach ($collection as $key => $value) {
932 1
            $newValue = getOrDefault($replacementMap, $value, $value);
933 1
            yield $key => $newValue;
934 1
        }
935 1
    };
936
937 1
    return new Collection($generatorFactory);
938
}
939
940
/**
941
 * Returns a lazy collection of reduction steps.
942
 *
943
 * @param array|Traversable $collection
944
 * @param callable $function
945
 * @param mixed $startValue
946
 * @return Collection
947
 */
948 View Code Duplication
function reductions($collection, callable $function, $startValue)
1 ignored issue
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
949
{
950
    $generatorFactory = function () use ($collection, $function, $startValue) {
951 1
        $tmp = duplicate($startValue);
952
953 1
        yield $tmp;
954 1
        foreach ($collection as $key => $value) {
955 1
            $tmp = $function($tmp, $value, $key);
956 1
            yield $tmp;
957 1
        }
958 1
    };
959
960 1
    return new Collection($generatorFactory);
961
}
962
963
/**
964
 * Returns a lazy collection of every nth ($step) item in  $collection.
965
 *
966
 * @param array|Traversable $collection
967
 * @param int $step
968
 * @return Collection
969
 */
970
function takeNth($collection, $step)
971
{
972
    $generatorFactory = function () use ($collection, $step) {
973 1
        $index = 0;
974 1
        foreach ($collection as $key => $value) {
975 1
            if ($index % $step == 0) {
976 1
                yield $key => $value;
977 1
            }
978
979 1
            $index++;
980 1
        }
981 1
    };
982
983 1
    return new Collection($generatorFactory);
984
}
985
986
/**
987
 * Returns a lazy collection of collections of $numberOfItems items each, at $step step
988
 * apart. If $step is not supplied, defaults to $numberOfItems, i.e. the partitions
989
 * do not overlap. If a $padding collection is supplied, use its elements as
990
 * necessary to complete last partition up to $numberOfItems items. In case there are
991
 * not enough padding elements, return a partition with less than $numberOfItems items.
992
 *
993
 * @param array|Traversable $collection
994
 * @param $numberOfItems
995
 * @param int $step
996
 * @param array|Traversable $padding
997
 * @return Collection
998
 */
999
function partition($collection, $numberOfItems, $step = -1, $padding = [])
1000
{
1001
    $generatorFactory = function () use ($collection, $numberOfItems, $step, $padding) {
1002 1
        $buffer = [];
1003 1
        $itemsToSkip = 0;
1004 1
        $tmpStep = $step ?: $numberOfItems;
1005
1006 1
        foreach ($collection as $key => $value) {
1007 1
            if (count($buffer) == $numberOfItems) {
1008 1
                yield dereferenceKeyValue($buffer);
1009
1010 1
                $buffer = array_slice($buffer, $tmpStep);
1011 1
                $itemsToSkip =  $tmpStep - $numberOfItems;
1012 1
            }
1013
1014 1
            if ($itemsToSkip <= 0) {
1015 1
                $buffer[] = [$key, $value];
1016 1
            } else {
1017 1
                $itemsToSkip--;
1018
            }
1019 1
        }
1020
1021 1
        yield take(
1022 1
            concat(dereferenceKeyValue($buffer), $padding),
1023
            $numberOfItems
1024 1
        );
1025 1
    };
1026
1027 1
    return new Collection($generatorFactory);
1028
}
1029
1030
/**
1031
 * Returns a lazy collection created by partitioning $collection each time $function returned a different value.
1032
 *
1033
 * @param array|Traversable $collection
1034
 * @param callable $function
1035
 * @return Collection
1036
 */
1037
function partitionBy($collection, callable $function)
1038
{
1039
    $generatorFactory = function () use ($collection, $function) {
1040 1
        $result = null;
1041 1
        $buffer = [];
1042
1043 1
        foreach ($collection as $key => $value) {
1044 1
            $newResult = $function($value, $key);
1045
1046 1
            if (!empty($buffer) && $result != $newResult) {
1047 1
                yield dereferenceKeyValue($buffer);
1048 1
                $buffer = [];
1049 1
            }
1050
1051 1
            $result = $newResult;
1052 1
            $buffer[] = [$key, $value];
1053 1
        }
1054
1055 1
        if (!empty($buffer)) {
1056 1
            yield dereferenceKeyValue($buffer);
1057 1
        }
1058 1
    };
1059
1060 1
    return new Collection($generatorFactory);
1061
}
1062
1063
/**
1064
 * Returns nth ($position) item from $collection. If $position is greater than $collection size, throws ItemNotFound.
1065
 *
1066
 * @param array|Traversable $collection
1067
 * @param int $position
1068
 * @return mixed
1069
 */
1070
function getNth($collection, $position)
1071
{
1072 16
    return get(values($collection), $position);
1073
}
1074
1075
/**
1076
 * Returns a lazy collection of $value repeated $times times. If $times is not provided the collection is infinite.
1077
 *
1078
 * @param mixed $value
1079
 * @param int $times
1080
 * @return Collection
1081
 */
1082
function repeat($value, $times = -1)
1083
{
1084
    $generatorFactory = function () use ($value, $times) {
1085 3
        $tmpTimes = $times;
1086
1087 3
        while ($tmpTimes != 0) {
1088 3
            yield $value;
1089
1090 3
            $tmpTimes = $tmpTimes < 0 ? -1 : $tmpTimes - 1;
1091 3
        }
1092 3
    };
1093
1094 3
    return new Collection($generatorFactory);
1095
}
1096
1097
/**
1098
 * Returns a lazy collection of numbers starting at $start, incremented by $step until $end is reached.
1099
 *
1100
 * @param int $start
1101
 * @param int|null $end
1102
 * @param int $step
1103
 * @return Collection
1104
 */
1105
function range($start = 0, $end = null, $step = 1)
1106
{
1107
    $generatorFactory = function () use ($start, $end, $step) {
1108 2
        return iterate(
1109 2
            $start,
1110
            function($value) use ($step, $end) {
1111 2
                $result = $value + $step;
1112
1113 2
                if ($end !== null && $result > $end) {
1114 1
                    throw new NoMoreItems;
1115
                }
1116
1117 2
                return $result;
1118
            }
1119 2
        );
1120 2
    };
1121
1122 2
    return new Collection($generatorFactory);
1123
}
1124
1125
/**
1126
 * Returns true if $input is array or Traversable object.
1127
 *
1128
 * @param mixed $input
1129
 * @return bool
1130
 */
1131
function isCollection($input)
1132
{
1133 15
    return is_array($input) || $input instanceof Traversable;
1134
}
1135
1136
/**
1137
 * Returns duplicated/cloned $input that has no relation to the original one. Used for making sure there are no side
1138
 * effect in functions.
1139
 *
1140
 * @param $input
1141
 * @return mixed
1142
 */
1143
function duplicate($input)
1144
{
1145 8
    if (is_array($input)) {
1146
        return toArray(
1147
            map(
1148
                $input,
1149
                function($i) {
1150
                    return duplicate($i);
1151
                }
1152
            )
1153
        );
1154 8
    } elseif (is_object($input)) {
1155 2
        return clone $input;
1156
    } else {
1157 8
        return $input;
1158
    }
1159
}
1160
1161
/**
1162
 * Transforms [[$key, $value], [$key2, $value2]] into [$key => $value, $key2 => $value2]. Used as a helper
1163
 *
1164
 * @param array|Traversable $collection
1165
 * @return Collection
1166
 */
1167
function dereferenceKeyValue($collection)
1168
{
1169
    $generatorFactory = function () use ($collection) {
1170 5
        foreach ($collection as $value) {
1171 5
            yield $value[0] => $value[1];
1172 5
        }
1173 6
    };
1174
1175 6
    return new Collection($generatorFactory);
1176
}
1177
1178
/**
1179
 * Realizes collection - turns lazy collection into non-lazy one by iterating over it and storing the key/values.
1180
 *
1181
 * @param array|Traversable $collection
1182
 * @return Collection
1183
 */
1184
function realize($collection)
1185
{
1186 1
    return dereferenceKeyValue(
1187 1
        toArray(
1188 1
            map(
1189 1
                $collection,
1190
                function ($value, $key) {
1191 1
                    return [$key, $value];
1192
                }
1193 1
            )
1194 1
        )
1195 1
    );
1196
}
1197
1198
/**
1199
 * Returns the second item of $collection or throws ItemNotFound if $collection is empty or has 1 item.
1200
 *
1201
 * @param array|Traversable $collection
1202
 * @return mixed
1203
 */
1204
function second($collection)
1205
{
1206 2
    return first(drop($collection, 1));
1207
}
1208
1209
1210
/**
1211
 * Combines $keys and $values into a lazy collection. The resulting collection has length equal to the size of smaller
1212
 * argument.
1213
 *
1214
 * @param array|Traversable $keys
1215
 * @param array|Traversable $values
1216
 * @return Collection
1217
 */
1218
function combine($keys, $values)
1219
{
1220
    $generatorFactory = function () use ($keys, $values) {
1221 1
        $keyCollection = new Collection($keys);
1222 1
        $valueCollection = new Collection($values);
1223 1
        $valueCollection->rewind();
1224
1225 1
        foreach ($keyCollection as $key) {
1226 1
            if (!$valueCollection->valid()) {
1227 1
                break;
1228
            }
1229
1230 1
            yield $key => $valueCollection->current();
1231 1
            $valueCollection->next();
1232 1
        }
1233 1
    };
1234
1235 1
    return new Collection($generatorFactory);
1236
}
1237
1238
/**
1239
 * Returns a lazy collection without the items associated to any of the keys from $keys.
1240
 *
1241
 * @param array|Traversable $collection
1242
 * @param array|Traversable $keys
1243
 * @return Collection
1244
 */
1245
function except($collection, $keys)
1246
{
1247 1
    $keys = toArray(values($keys));
1248
1249 1
    return reject(
1250 1
        $collection,
1251
        function ($value, $key) use ($keys) {
1252 1
            return in_array($key, $keys);
1253
        }
1254 1
    );
1255
}
1256
1257
/**
1258
 * Returns a lazy collection of items associated to any of the keys from $keys.
1259
 *
1260
 * @param array|Traversable $collection
1261
 * @param array|Traversable $keys
1262
 * @return Collection
1263
 */
1264
function only($collection, $keys)
1265
{
1266 2
    $keys = toArray(values($keys));
1267
1268 2
    return filter(
1269 2
        $collection,
1270
        function ($value, $key) use ($keys) {
1271 2
            return in_array($key, $keys);
1272
        }
1273 2
    );
1274
}
1275
1276
/**
1277
 * Returns a lazy collection of items that are in $collection but are not in any of the other arguments. Note that the
1278
 * ...$collections are iterated non-lazily.
1279
 *
1280
 * @param array|Traversable $collection
1281
 * @param array|Traversable ...$collections
1282
 * @return Collection
1283
 */
1284
function difference($collection, ...$collections)
1285
{
1286 1
    $valuesToCompare = toArray(values(concat(...$collections)));
1287
    $generatorFactory = function () use ($collection, $valuesToCompare) {
1288 1
        foreach ($collection as $key => $value) {
1289 1
            if (!in_array($value, $valuesToCompare)) {
1290 1
                yield $key => $value;
1291 1
            }
1292 1
        }
1293 1
    };
1294
1295 1
    return new Collection($generatorFactory);
1296
}
1297
1298
/**
1299
 * Returns a lazy collection where keys and values are flipped.
1300
 *
1301
 * @param array|Traversable $collection
1302
 * @return Collection
1303
 */
1304
function flip($collection)
1305
{
1306
    $generatorFactory = function () use ($collection) {
1307 1
        foreach ($collection as $key => $value) {
1308 1
            yield $value => $key;
1309 1
        }
1310 1
    };
1311
1312 1
    return new Collection($generatorFactory);
1313
}
1314
1315
/**
1316
 * Checks for the existence of an item with key $key in $collection.
1317
 *
1318
 * @param array|Traversable $collection
1319
 * @param mixed $key
1320
 * @return bool
1321
 */
1322
function has($collection, $key)
1323
{
1324
    try {
1325 2
        get($collection, $key);
1326 2
        return true;
1327 2
    } catch (ItemNotFound $e) {
1328 2
        return false;
1329
    }
1330
}
1331
1332
/**
1333
 * Returns a lazy collection of non-lazy collections of items from nth position from each passed collection. Stops when
1334
 * any of the collections don't have an item at the nth position.
1335
 *
1336
 * @param array|Traversable[] ...$collections
1337
 * @return Collection
1338
 */
1339
function zip(...$collections)
1340
{
1341 1
    $normalizedCollections = [];
1342 1
    foreach ($collections as $collection) {
1343 1
        $traversable = new Collection($collection);
1344 1
        $traversable->rewind();
1345 1
        $normalizedCollections[] = $traversable;
1346 1
    }
1347
1348
    $generatorFactory = function () use ($normalizedCollections) {
1349 1
        while (true) {
1350 1
            $isMissingItems = false;
1351 1
            $zippedItem = new Collection([]);
1352
1353 1
            foreach ($normalizedCollections as $collection) {
1354 1
                if (!$collection->valid()) {
1355 1
                    $isMissingItems = true;
1356 1
                    break;
1357
                }
1358
1359 1
                $zippedItem = append($zippedItem, $collection->current(), $collection->key());
1360 1
                $collection->next();
1361 1
            }
1362
1363 1
            if (!$isMissingItems) {
1364 1
                yield $zippedItem;
1365 1
            } else {
1366 1
                break;
1367
            }
1368 1
        }
1369 1
    };
1370
1371 1
    return new Collection($generatorFactory);
1372
}
1373
1374
/**
1375
 * Returns a lazy collection of data extracted from $collection items by dot separated key path. Supports the *
1376
 * wildcard. If a key contains \ or * it must be escaped using \ character.
1377
 *
1378
 * @param array|Traversable $collection
1379
 * @param mixed $keyPath
1380
 * @return Collection
1381
 */
1382
function extract($collection, $keyPath)
1383
{
1384 1
    $error = !preg_match_all('/(.*[^\\\])(?:\.|$)/U', $keyPath, $matches);
1385
1386 1
    if ($error || count($matches) != 2) {
1387
        throw new InvalidArgument;
1388
    }
1389
1390 1
    $pathParts = $matches[1];
1391
1392
    $extractor = function ($coll) use ($pathParts) {
1393 1
        foreach ($pathParts as $pathPart) {
1394 1
            $coll = flatten(filter($coll, '\DusanKasan\Knapsack\isCollection'), 1);
1395
1396 1
            if ($pathPart != '*') {
1397 1
                $pathPart = str_replace(['\.', '\*'], ['.', '*'], $pathPart);
1398 1
                $coll = values(only($coll, [$pathPart]));
1399 1
            }
1400 1
        }
1401
1402 1
        return $coll;
1403 1
    };
1404
1405
    $generatorFactory = function () use ($collection, $extractor) {
1406 1
        foreach ($collection as $item) {
1407 1
            foreach ($extractor([$item]) as $extracted) {
1408 1
                yield $extracted;
1409 1
            }
1410 1
        }
1411 1
    };
1412
1413
1414 1
    return new Collection($generatorFactory);
1415
}
1416