Passed
Pull Request — master (#49)
by
unknown
10:35 queued 06:43
created

itertools.php ➔ collapse()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 7
ccs 3
cts 3
cp 1
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Zicht Online <http://zicht.nl>
4
 */
5
6
namespace Zicht\Itertools;
7
8
use Zicht\Itertools\conversions;
9
use Zicht\Itertools\lib\AccumulateIterator;
10
use Zicht\Itertools\lib\ChainIterator;
11
use Zicht\Itertools\lib\CountIterator;
12
use Zicht\Itertools\lib\CycleIterator;
13
use Zicht\Itertools\lib\FilterIterator;
14
use Zicht\Itertools\lib\GroupbyIterator;
15
use Zicht\Itertools\lib\Interfaces\AccumulateInterface;
16
use Zicht\Itertools\lib\Interfaces\AllInterface;
17
use Zicht\Itertools\lib\Interfaces\ChainInterface;
18
use Zicht\Itertools\lib\Interfaces\CollapseInterface;
19
use Zicht\Itertools\lib\Interfaces\CycleInterface;
20
use Zicht\Itertools\lib\Interfaces\FilterInterface;
21
use Zicht\Itertools\lib\Interfaces\FiniteIterableInterface;
22
use Zicht\Itertools\lib\Interfaces\FirstInterface;
23
use Zicht\Itertools\lib\Interfaces\GroupByInterface;
24
use Zicht\Itertools\lib\Interfaces\LastInterface;
25
use Zicht\Itertools\lib\Interfaces\MapByInterface;
26
use Zicht\Itertools\lib\Interfaces\ReduceInterface;
27
use Zicht\Itertools\lib\Interfaces\ReversedInterface;
28
use Zicht\Itertools\lib\Interfaces\SliceInterface;
29
use Zicht\Itertools\lib\Interfaces\SortedInterface;
30
use Zicht\Itertools\lib\Interfaces\UniqueInterface;
31
use Zicht\Itertools\lib\Interfaces\ZipInterface;
32
use Zicht\Itertools\lib\IterableIterator;
33
use Zicht\Itertools\lib\MapByIterator;
34
use Zicht\Itertools\lib\MapIterator;
35
use Zicht\Itertools\lib\RepeatIterator;
36
use Zicht\Itertools\lib\ReversedIterator;
37
use Zicht\Itertools\lib\SliceIterator;
38
use Zicht\Itertools\lib\SortedIterator;
39
use Zicht\Itertools\lib\UniqueIterator;
40
use Zicht\Itertools\lib\ZipIterator;
41
use Zicht\Itertools\reductions;
42
43
/**
44
 * Transforms anything into an \Iterator or throws an \InvalidArgumentException
45
 *
46
 * @param array|string|\Iterator $iterable
47
 * @return \Iterator
48
 *
49
 * @deprecated Use conversions\mixed_to_iterator instead, will be removed in version 3.0
50
 */
51
function mixedToIterator($iterable) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
52
{
53
    return conversions\mixed_to_iterator($iterable);
54
}
55
56
/**
57
 * Try to transforms something into a \Closure
58
 *
59
 * @param null|\Closure $closure
60
 * @return \Closure
61
 *
62
 * @deprecated Use conversions\mixed_to_closure instead, will be removed in version 3.0
63
 */
64
function mixedToClosure($closure) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
65
{
66
    return conversions\mixed_to_closure($closure);
67
}
68
69
/**
70
 * Try to transforms something into a \Closure that gets a value from $strategy
71
 *
72
 * @param null|string|\Closure $strategy
73
 * @return \Closure
74
 *
75
 * @deprecated Use Conversions::mixedToValueGetter instead, will be removed in version 3.0
76
 */
77
function mixedToValueGetter($strategy) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
78
{
79
    return conversions\mixed_to_value_getter($strategy);
80
}
81
82
/**
83
 * Try to transform something into a \Closure
84
 *
85
 * @param string|\Closure $closure
86
 * @return \Closure
87
 *
88
 * @deprecated Will be removed in version 3.0, no replacement will be needed
89
 */
90
function mixedToOperationClosure($closure) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
91
{
92
    if (is_string($closure)) {
93
        $closure = reductions\get_reduction($closure, $closure);
0 ignored issues
show
Deprecated Code introduced by
The function Zicht\Itertools\reductions\get_reduction() has been deprecated with message: please use the reduction functions directly, will be removed in version 3.0

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
94
    }
95
96
    if (!($closure instanceof \Closure)) {
97
        throw new \InvalidArgumentException('Argument $closure must be a \Closure or string (i.e. "add", "join", etc)');
98
    }
99
100
    return $closure;
101
}
102
103
/**
104
 * Make an iterator that returns accumulated sums
105
 *
106
 * If the optional $closure argument is supplied, it should be a string:
107
 * add, sub, mul, min, or max.  Or it can be a \Closure taking two
108
 * arguments that will be used to instead of addition.
109
 *
110
 * > accumulate([1,2,3,4,5])
111
 * 1 3 6 10 15
112
 *
113
 * > accumulate(['One', 'Two', 'Three'], function ($a, $b) { return $a . $b; })
114
 * 'One' 'OneTwo' 'OneTwoThree'
115
 *
116
 * @param array|string|\Iterator $iterable
117
 * @param string|\Closure $closure
118
 * @return AccumulateIterator
119
 */
120
function accumulate($iterable, $closure = 'add')
121
{
122 16
    if (!($iterable instanceof AccumulateInterface)) {
123 15
        $iterable = iterable($iterable);
124
    }
125
126 14
    return $iterable->accumulate($closure);
127
}
128
129
/**
130
 * Reduce an iterator to a single value
131
 *
132
 * > reduce([1,2,3])
133
 * 6
134
 *
135
 * > reduce([1,2,3], 'max')
136
 * 3
137
 *
138
 * > reduce([1,2,3], 'sub', 10)
139
 * 4
140
 *
141
 * > reduce([], 'min', 1)
142
 * 1
143
 *
144
 * @param array|string|\Iterator $iterable
145
 * @param string|\Closure $closure
146
 * @param mixed $initializer
147
 * @return mixed
148
 */
149
function reduce($iterable, $closure = 'add', $initializer = null)
150
{
151 17
    if (!($iterable instanceof ReduceInterface)) {
152 17
        $iterable = iterable($iterable);
153
    }
154
155 14
    return $iterable->reduce($closure, $initializer);
156
}
157
158
function collapse($iterable) {
159 6
    if (!($iterable instanceof CollapseInterface)) {
160 6
        $iterable = iterable($iterable);
161
    }
162
163 3
    return $iterable->collapse();
164
}
165
166
/**
167
 * Make an iterator that contains all consecutive elements from all provided iterables.
168
 *
169
 * The resulting iterator contains elements from the first iterable in the parameters
170
 * until it is exhausted, then proceeds to the next iterable in the parameters, until
171
 * all the iterables are exhausted.  Used for creating consecutive
172
 * sequences as a single sequence
173
 *
174
 * > chain([1, 2, 3], [4, 5, 6])
175
 * 1 2 3 4 5 6
176
 *
177
 * > chain('ABC', 'DEF')
178
 * A B C D E F
179
 *
180
 * @return ChainIterator
181
 */
182
function chain()
183
{
184
    // note, once we stop supporting php 5.5, we can rewrite the code below
185
    // to the chain(...$iterables) structure.
186
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
187
188 12
    $args = func_get_args();
189 12
    if (sizeof($args) > 0) {
190 11
        list($iterable) = array_slice($args, 0, 1);
191 11
        $iterables = array_slice($args, 1);
192
    } else {
193 1
        $iterable = null;
194 1
        $iterables = [];
195
    }
196
197 12
    if (!($iterable instanceof ChainInterface)) {
198 12
        $iterable = iterable($iterable);
199
    }
200
201 9
    return call_user_func_array([$iterable, 'chain'], $iterables);
202
}
203
204
/**
205
 * Make an iterator that returns evenly spaced values starting with
206
 * number $start
207
 *
208
 * > count(10)
209
 * 10 11 12 13 14 ...
210
 *
211
 * > count(2.5, 0.5)
212
 * 2.5 3.0 3.5 4.0 ...
213
 *
214
 * @param int|float $start
215
 * @param int|float $step
216
 * @return CountIterator
217
 */
218
function count($start = 0, $step = 1)
219
{
220 36
    if (!(is_int($start) || is_float($start))) {
221 3
        throw new \InvalidArgumentException('Argument $start must be an integer or float');
222
    }
223
224 33
    if (!(is_int($step) || is_float($step))) {
225 3
        throw new \InvalidArgumentException('Argument $step must be an integer or float');
226
    }
227
228 30
    return new CountIterator($start, $step);
229
}
230
231
/**
232
 * Make an iterator returning elements from the $iterable and saving a
233
 * copy of each.  When the iterable is exhausted, return elements from
234
 * the saved copy, repeating indefinitely
235
 *
236
 * > cycle('ABCD')
237
 * A B C D A B C D A B C D ...
238
 *
239
 * @param array|string|\Iterator $iterable
240
 * @return CycleIterator
241
 */
242
function cycle($iterable)
243
{
244 12
    if (!($iterable instanceof CycleInterface)) {
245 12
        $iterable = iterable($iterable);
246
    }
247
248 9
    return $iterable->cycle();
249
}
250
251
/**
252
 * Make an iterator returning values from $iterable and keys from
253
 * $strategy
254
 *
255
 * When $strategy is a string, the key is obtained through one of
256
 * the following:
257
 * 1. $value->{$strategy}, when $value is an object and
258
 *    $strategy is an existing property,
259
 * 2. call $value->{$strategy}(), when $value is an object and
260
 *    $strategy is an existing method,
261
 * 3. $value[$strategy], when $value is an array and $strategy
262
 *    is an existing key,
263
 * 4. otherwise the key will default to null.
264
 *
265
 * Alternatively $strategy can be a closure.  In this case the
266
 * $strategy closure is called with each value in $iterable and the
267
 * key will be its return value.
268
 *
269
 * > $list = [['id'=>1, 'title'=>'one'], ['id'=>2, 'title'=>'two']]
270
 * > mapBy('id', $list)
271
 * 1=>['id'=>1, 'title'=>'one'] 2=>['id'=>2, 'title'=>'two']
272
 *
273
 * @param null|string|\Closure $strategy
274
 * @param array|string|\Iterator $iterable
275
 * @return MapByIterator
276
 */
277
function map_by($strategy, $iterable)
278
{
279
    // In version 3.0 mapBy and map_by will be removed
280
    // as its functionality will be merged into map.
281
282 23
    if (!($iterable instanceof MapByInterface)) {
283 23
        $iterable = iterable($iterable);
284
    }
285
286 23
    return $iterable->mapBy($strategy);
287
}
288
289
/**
290
 * Make an iterator returning values from $iterable and keys from
291
 * $strategy
292
 *
293
 * @param null|string|\Closure $strategy
294
 * @param array|string|\Iterator $iterable
295
 * @return MapByIterator
296
 *
297
 * @deprecated Please use map_by, will be removed in version 3.0
298
 */
299
function mapBy($strategy, $iterable) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
300
{
301
    return map_by($strategy, $iterable);
302
}
303
304
/**
305
 * Make an iterator returning values from $iterable and keys from
306
 * $strategy
307
 *
308
 * @param null|string|\Closure $strategy
309
 * @param array|string|\Iterator $iterable
310
 * @return MapByIterator
311
 *
312
 * @deprecated use map_by() instead, will be removed in version 3.0
313
 */
314
function keyCallback($strategy, $iterable) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
315
{
316
    return map_by($strategy, $iterable);
317
}
318
319
/**
320
 * Make an iterator that applies $strategy to every entry in the iterables
321
 *
322
 * If one iterable is passed, $strategy is called for each entry in
323
 * the $iterable, where the first argument is the value and the
324
 * second argument is the key of the entry
325
 *
326
 * If more than one iterable is passed, $strategy is called with the
327
 * values and the keys from the iterables.  For example, the first
328
 * call to $strategy will be:
329
 * $strategy($value_iterable1, $value_iterable2, $key_iterable2, $key_iterable2)
330
 *
331
 * With multiple iterables, the iterator stops when the shortest
332
 * iterable is exhausted.
333
 *
334
 * > $minimal = function ($value) { return min(3, $value); };
335
 * > map($minimal, [1, 2, 3, 4]);
336
 * 3 3 3 4
337
 *
338
 * > $average = function ($value1, $value2) { return ($value1 + $value2) / 2; };
339
 * > map($average, [1, 2, 3], [4, 5, 6]);
340
 * 2.5 3.5 4.5
341
 *
342
 * @param null|string|\Closure $strategy
343
 * @param array|string|\Iterator $iterable Additional $iterable parameters may follow
344
 * @return MapIterator
345
 */
346 View Code Duplication
function map($strategy, $iterable)
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...
347
{
348
    // note, once we stop supporting php 5.5, we can rewrite the code below
349
    // to the map(...$iterables) structure.
350
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
351
352 32
    if (func_num_args() > 2) {
353 10
        $iterables = array_slice(func_get_args(), 2);
354
    } else {
355 22
        $iterables = [];
356
    }
357
358 32
    if (!($iterable instanceof ChainInterface)) {
359 31
        $iterable = iterable($iterable);
360
    }
361
362 32
    return call_user_func_array([$iterable, 'map'], array_merge([$strategy], $iterables));
363
}
364
365
/**
366
 * Select values from the iterator by applying a function to each of the iterator values, i.e., mapping it to the
367
 * value with a strategy based on the input, similar to map_key
368
 *
369
 * @param null|string|\Closure $strategy
370
 * @param array|string|\Iterator $iterable
371
 * @param bool $flatten
372
 * @return array|MapIterator
373
 *
374
 * @deprecated Please use map(...)->values() instead (when flatten true), will be removed in version 3.0
375
 */
376
function select($strategy, $iterable, $flatten = true)
377
{
378
    if (!is_bool($flatten)) {
379
        throw new \InvalidArgumentException('Argument $FLATTEN must be a boolean');
380
    }
381
382
    $ret = new MapIterator(
383
        conversions\mixed_to_value_getter($strategy),
384
        conversions\mixed_to_iterator($iterable)
385
    );
386
    if ($flatten) {
387
        return $ret->values();
388
    }
389
    return $ret;
390
}
391
392
/**
393
 * Make an iterator that returns $mixed over and over again.  Runs
394
 * indefinitely unless the $times argument is specified
395
 *
396
 * > repeat(2)
397
 * 2 2 2 2 2 ...
398
 *
399
 * > repeat(10, 3)
400
 * 10 10 10
401
 *
402
 * @param mixed $mixed
403
 * @param null|int $times
404
 * @return RepeatIterator
405
 */
406
function repeat($mixed, $times = null)
407
{
408 9
    if (!(is_null($times) || (is_int($times) && $times >= 0))) {
409 4
        throw new \InvalidArgumentException('Argument $times must be null or a positive integer');
410
    }
411
412 5
    return new RepeatIterator($mixed, $times);
413
}
414
415
/**
416
 * Make an iterator that returns consecutive groups from the
417
 * $iterable.  Generally, the $iterable needs to already be sorted on
418
 * the same key function
419
 *
420
 * When $strategy is a string, the key is obtained through one of
421
 * the following:
422
 * 1. $value->{$strategy}, when $value is an object and
423
 *    $strategy is an existing property,
424
 * 2. call $value->{$strategy}(), when $value is an object and
425
 *    $strategy is an existing method,
426
 * 3. $value[$strategy], when $value is an array and $strategy
427
 *    is an existing key,
428
 * 4. otherwise the key will default to null.
429
 *
430
 * Alternatively $strategy can be a closure.  In this case the
431
 * $strategy closure is called with each value in $iterable and the
432
 * key will be its return value.  $strategy is called with two
433
 * parameters: the value and the key of the iterable as the first and
434
 * second parameter, respectively.
435
 *
436
 * The operation of groupBy() is similar to the uniq filter in Unix.
437
 * It generates a break or new group every time the value of the key
438
 * function changes (which is why it is usually necessary to have
439
 * sorted the data using the same key function).  That behavior
440
 * differs from SQL's GROUP BY which aggregates common elements
441
 * regardless of their input order.
442
 *
443
 * > $list = [['type'=>'A', 'title'=>'one'], ['type'=>'A', 'title'=>'two'], ['type'=>'B', 'title'=>'three']]
444
 * > groupby('type', $list)
445
 * 'A'=>[['type'=>'A', 'title'=>'one'], ['type'=>'A', 'title'=>'two']] 'B'=>[['type'=>'B', 'title'=>'three']]
446
 *
447
 * @param null|string|\Closure $strategy
448
 * @param array|string|\Iterator $iterable
449
 * @param boolean $sort
450
 * @return GroupbyIterator
451
 */
452
function group_by($strategy, $iterable, $sort = true)
453
{
454 16
    if (!($iterable instanceof GroupByInterface)) {
455 16
        $iterable = iterable($iterable);
456
    }
457
458 16
    return $iterable->groupBy($strategy, $sort);
459
}
460
461
/**
462
 * Make an iterator that returns consecutive groups from the
463
 * $iterable.  Generally, the $iterable needs to already be sorted on
464
 * the same key function
465
 *
466
 * @param null|string|\Closure $strategy
467
 * @param array|string|\Iterator $iterable
468
 * @param boolean $sort
469
 * @return GroupbyIterator
470
 *
471
 * @deprecated Please use group_by(...)->values() instead (when flatten true), will be removed in version 3.0
472
 */
473
function groupBy($strategy, $iterable, $sort = true) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
474
{
475
    return group_by($strategy, $iterable, $sort);
476
}
477
478
/**
479
 * Make an iterator that returns the values from $iterable sorted by
480
 * $strategy
481
 *
482
 * When determining the order of two entries the $strategy is called
483
 * twice, once for each value, and the results are used to determine
484
 * the order.  $strategy is called with two parameters: the value and
485
 * the key of the iterable as the first and second parameter, respectively.
486
 *
487
 * When $reverse is true the order of the results are reversed.
488
 *
489
 * The sorted() function is guaranteed to be stable.  A sort is stable
490
 * if it guarantees not to change the relative order of elements that
491
 * compare equal.  this is helpful for sorting in multiple passes (for
492
 * example, sort by department, then by salary grade).  This also
493
 * holds up when $reverse is true.
494
 *
495
 * > $list = [['type'=>'B', 'title'=>'second'], ['type'=>'C', 'title'=>'third'], ['type'=>'A', 'title'=>'first']]
496
 * > sorted('type', $list)
497
 * ['type'=>'A', 'title'=>'first'] ['type'=>'B', 'title'=>'second']] ['type'=>'C', 'title'=>'third']
498
 *
499
 * @param null|string|\Closure $strategy
500
 * @param array|string|\Iterator $iterable
501
 * @param boolean $reverse
502
 * @return SortedIterator
503
 */
504
function sorted($strategy, $iterable, $reverse = false)
505
{
506 22
    if (!($iterable instanceof SortedInterface)) {
507 21
        $iterable = iterable($iterable);
508
    }
509
510 22
    return $iterable->sorted($strategy, $reverse);
511
}
512
513
/**
514
 * Make an iterator that returns values from $iterable where the
515
 * $strategy determines that the values are not empty
516
 *
517
 * An optional $strategy may be given, this must be either null,
518
 * a string, or a \Closure.
519
 *
520
 * Following the (optional) $strategy, one or more $iterable instances
521
 * must be given.  They must be either an array, a string, or an \Iterator.
522
 *
523
 * @return FilterIterator
524
 */
525 View Code Duplication
function filter()
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...
526
{
527
    // note, once we stop supporting php 5.5, we can rewrite the code below
528
    // to the filter(...$iterables) structure.
529
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
530
531 9
    $args = func_get_args();
532 9
    switch (sizeof($args)) {
533 9
        case 1:
534 3
            $strategy = null;
535 3
            $iterable = $args[0];
536 3
            break;
537
538 6
        case 2:
539 5
            $strategy = $args[0];
540 5
            $iterable = $args[1];
541 5
            break;
542
543
        default:
544 1
            throw new \InvalidArgumentException('filter requires either one (iterable) or two (strategy, iterable) arguments');
545
    }
546
547 8
    if (!($iterable instanceof FilterInterface)) {
548 7
        $iterable = iterable($iterable);
549
    }
550
551 5
    return $iterable->filter($strategy);
552
}
553
554
/**
555
 * Make an iterator that returns values from $iterable where the
556
 * $strategy determines that the values are not empty
557
 *
558
 * An $strategy must be given, this must be either null, a string,
559
 * or a \Closure.
560
 *
561
 * Following the $strategy, an optional $closure may be given, this
562
 * closure is called to determine is the value (which results from
563
 * $strategy) is or is not filtered.  Note that without providing a
564
 * $closure, the function !empty(...) is used instead.
565
 *
566
 * Following the (optional) $closure, one or more $iterable instances
567
 * must be given.  They must be either an array, a string, or an \Iterator.
568
 *
569
 * @return FilterIterator
570
 *
571
 * @deprecated Use filter() instead, will be removed in version 3.0
572
 */
573
function filterBy() // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
574
{
575
    // note, once we stop supporting php 5.5, we can rewrite the code below
576
    // to the filterBy(...$iterables) structure.
577
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
578
579
    $args = func_get_args();
580
    switch (sizeof($args)) {
581 View Code Duplication
        case 2:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
582
            $strategy = conversions\mixed_to_value_getter($args[0]);
583
            $closure = function ($value, $key) use ($strategy) {
584
                $tempVarPhp54 = call_user_func($strategy, $value, $key);
585
                return !empty($tempVarPhp54);
586
            };
587
            $iterable = conversions\mixed_to_iterator($args[1]);
588
            break;
589
590 View Code Duplication
        case 3:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
591
            $strategy = conversions\mixed_to_value_getter($args[0]);
592
            $userClosure = $args[1];
593
            $closure = function ($value, $key) use ($strategy, $userClosure) {
594
                return call_user_func($userClosure, call_user_func($strategy, $value, $key));
595
            };
596
            $iterable = conversions\mixed_to_iterator($args[2]);
597
            break;
598
599
        default:
600
            throw new \InvalidArgumentException('filterBy requires either two (strategy, iterable) or three (strategy, closure, iterable) arguments');
601
    }
602
603
    return new FilterIterator($closure, $iterable);
604
}
605
606
/**
607
 * Returns an iterator where one or more iterables are zipped together
608
 *
609
 * This function returns a list of tuples, where the i-th tuple contains
610
 * the i-th element from each of the argument sequences or iterables.
611
 *
612
 * The returned list is truncated in length to the length of the
613
 * shortest argument sequence.
614
 *
615
 * > zip([1, 2, 3], ['a', 'b', 'c'])
616
 * [1, 'a'] [2, 'b'] [3, 'c']
617
 *
618
 * @param array|string|\Iterator $iterable Additional $iterable parameters may follow
619
 * @return ZipIterator
620
 */
621 View Code Duplication
function zip($iterable)
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...
622
{
623
    // note, once we stop supporting php 5.5, we can rewrite the code below
624
    // to the zip(...$iterables) structure.
625
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
626
627 11
    if (func_num_args() > 1) {
628 6
        $iterables = array_slice(func_get_args(), 1);
629
    } else {
630 5
        $iterables = [];
631
    }
632
633 11
    if (!($iterable instanceof ZipInterface)) {
634 11
        $iterable = iterable($iterable);
635
    }
636
637 8
    return call_user_func_array([$iterable, 'zip'], $iterables);
638
}
639
640
/**
641
 * Returns an iterable with all the elements from $iterable reversed
642
 *
643
 * @param array|string|\Iterator $iterable
644
 * @return ReversedIterator
645
 */
646
function reversed($iterable)
647
{
648 6
    if (!($iterable instanceof ReversedInterface)) {
649 5
        $iterable = iterable($iterable);
650
    }
651
652 3
    return $iterable->reversed();
653
}
654
655
/**
656
 * Returns an iterator where the values from $strategy are unique
657
 *
658
 * An optional $strategy may be given to specify the value which is used
659
 * to determine whether the element is unique.  When no $strategy is
660
 * given, the identity function is used, i.e. the value of the element
661
 * itself is used to determine whether the element is unique.
662
 *
663
 * Following the optional $strategy, a $iterable must be given.  Otherwise,
664
 * an \InvalidArgumentException will be raised.
665
 *
666
 * > unique([1, 1, 2, 2, 3, 3])
667
 * 1 2 3
668
 *
669
 * > unique('id', [['id' => 1, 'value' => 'a'], ['id' => 1, 'value' => 'b']])
670
 * ['id' => 1, 'value' => 'a']  # one element in this list
671
 *
672
 * @return UniqueIterator
673
 */
674 View Code Duplication
function unique()
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...
675
{
676 25
    $args = func_get_args();
677 25
    switch (sizeof($args)) {
678 25
        case 1:
679 8
            $strategy = null;
680 8
            $iterable = $args[0];
681 8
            break;
682
683 17
        case 2:
684 15
            $strategy = $args[0];
685 15
            $iterable = $args[1];
686 15
            break;
687
688
        default:
689 2
            throw new \InvalidArgumentException('unique requires either one (iterable) or two (strategy, iterable) arguments');
690
    }
691
692 23
    if (!($iterable instanceof UniqueInterface)) {
693 23
        $iterable = iterable($iterable);
694
    }
695
696 17
    return $iterable->unique($strategy);
697
}
698
699
/**
700
 * Returns an iterator where the values from $strategy are unique
701
 *
702
 * @param null|string|\Closure $strategy
703
 * @param array|string|\Iterator $iterable
704
 * @return UniqueIterator
705
 *
706
 * @deprecated use unique($strategy, $iterable) instead, will be removed in version 3.0
707
 */
708
function uniqueBy($strategy, $iterable) // phpcs:ignore Zicht.NamingConventions.Functions.GlobalNaming
709
{
710
    return unique($strategy, $iterable);
711
}
712
713
/**
714
 * Returns true when one or more element of $iterable is not empty, otherwise returns false
715
 *
716
 * An optional $strategy may be given to specify the value which is used
717
 * to determine weather the element evaluates to true.  When no $strategy is
718
 * given, the identity function is used, i.e. the value of the element
719
 * itself is used to determine weather the element evaluates to true.
720
 *
721
 * Following the optional $strategy, an $iterable may be given.  Its type may
722
 * be either array, string, or \Iterator.  When no $iterable is given, false
723
 * is returned.
724
 *
725
 * > any([0, '', false])
726
 * false
727
 *
728
 * > any([1, null, 3])
729
 * true
730
 *
731
 * @return boolean
732
 */
733 View Code Duplication
function any()
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...
734
{
735 19
    $args = func_get_args();
736 19
    switch (sizeof($args)) {
737 19
        case 1:
738 9
            $strategy = null;
739 9
            $iterable = $args[0];
740 9
            break;
741
742 10
        case 2:
743 8
            $strategy = $args[0];
744 8
            $iterable = $args[1];
745 8
            break;
746
747
        default:
748 2
            throw new \InvalidArgumentException('any requires either one (iterable) or two (strategy, iterable) arguments');
749
    }
750
751 17
    if (!($iterable instanceof AllInterface)) {
752 17
        $iterable = iterable($iterable);
753
    }
754
755 14
    return $iterable->any($strategy);
756
}
757
758
/**
759
 * Returns true when all elements of $iterable are not empty, otherwise returns false
760
 *
761
 * An optional $strategy may be given to specify the value which is used
762
 * to determine weather the element evaluates to true.  When no $strategy is
763
 * given, the identity function is used, i.e. the value of the element
764
 * itself is used to determine weather the element evaluates to true.
765
 *
766
 * Following the optional $strategy, an $iterable may be given.  Its type may
767
 * be either array, string, or \Iterator.  When no $iterable is given, true
768
 * is returned.
769
 *
770
 * > all([1, 'hello world', true])
771
 * true
772
 *
773
 * > all([1, null, 3])
774
 * false
775
 *
776
 * @return boolean
777
 */
778 View Code Duplication
function all()
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...
779
{
780 19
    $args = func_get_args();
781 19
    switch (sizeof($args)) {
782 19
        case 1:
783 9
            $strategy = null;
784 9
            $iterable = $args[0];
785 9
            break;
786
787 10
        case 2:
788 8
            $strategy = $args[0];
789 8
            $iterable = $args[1];
790 8
            break;
791
792
        default:
793 2
            throw new \InvalidArgumentException('all requires either one (iterable) or two (strategy, iterable) arguments');
794
    }
795
796 17
    if (!($iterable instanceof AllInterface)) {
797 17
        $iterable = iterable($iterable);
798
    }
799
800 14
    return $iterable->all($strategy);
801
}
802
803
/**
804
 * Make an iterator that contains a slice of $iterable
805
 *
806
 * The parameters $start and $end determine the range that will be taken
807
 * from the $iterable.  These values may be negative, in which case they
808
 * will indicate elements in $iterable starting at the end.
809
 *
810
 * > slice(['a', 'b', 'c', 'd', 'e', 1]
811
 * 'b', 'c', 'd', 'e'
812
 *
813
 * > slice(['a', 'b', 'c', 'd', 'e', -1]
814
 * 'e'
815
 *
816
 * > slice(['a', 'b', 'c', 'd', 'e', 1, 2]
817
 * 'b'
818
 *
819
 * > slice(['a', 'b', 'c', 'd', 'e', 1, -1]
820
 * 'b', 'c', 'd'
821
 *
822
 * @param array|string|\Iterator $iterable
823
 * @param int $start
824
 * @param null|int $end
825
 * @return SliceIterator
826
 */
827
function slice($iterable, $start, $end = null)
828
{
829 27
    if (!($iterable instanceof SliceInterface)) {
830 27
        $iterable = iterable($iterable);
831
    }
832
833 27
    return $iterable->slice($start, $end);
834
}
835
836
/**
837
 * Returns the first element of $iterable or returns $default when $iterable is empty
838
 *
839
 * > first([1, 2, 3])
840
 * 1
841
 *
842
 * > first([])
843
 * null
844
 *
845
 * @param array|string|\Iterator $iterable
846
 * @param mixed $default
847
 * @return mixed
848
 */
849
function first($iterable, $default = null)
850
{
851 9
    if (!($iterable instanceof FirstInterface)) {
852 9
        $iterable = iterable($iterable);
853
    }
854
855 5
    return $iterable->first($default);
856
}
857
858
/**
859
 * Returns the key of the first element of $iterable or returns $default when $iterable is empty
860
 *
861
 * > first_key([1, 2, 3])
862
 * 0
863
 *
864
 * > first_key([])
865
 * null
866
 *
867
 * @param array|string|\Iterator $iterable
868
 * @param mixed $default
869
 * @return mixed
870
 */
871
function first_key($iterable, $default = null)
872
{
873 5
    if (!($iterable instanceof FirstInterface)) {
874 5
        $iterable = iterable($iterable);
875
    }
876
877 5
    return $iterable->firstKey($default);
878
}
879
880
/**
881
 * Returns the last element of $iterable or returns $default when $iterable is empty
882
 *
883
 * > last([1, 2, 3])
884
 * 3
885
 *
886
 * > last([])
887
 * null
888
 *
889
 * @param array|string|\Iterator $iterable
890
 * @param mixed $default
891
 * @return mixed
892
 */
893
function last($iterable, $default = null)
894
{
895 9
    if (!($iterable instanceof LastInterface)) {
896 9
        $iterable = iterable($iterable);
897
    }
898
899 5
    return $iterable->last($default);
900
}
901
902
/**
903
 * Returns the key of the last element of $iterable or returns $default when $iterable is empty
904
 *
905
 * > last_key([1, 2, 3])
906
 * 2
907
 *
908
 * > last_key([])
909
 * null
910
 *
911
 * @param array|string|\Iterator $iterable
912
 * @param mixed $default
913
 * @return mixed
914
 */
915
function last_key($iterable, $default = null)
916
{
917 5
    if (!($iterable instanceof LastInterface)) {
918 5
        $iterable = iterable($iterable);
919
    }
920
921 5
    return $iterable->lastKey($default);
922
}
923
924
/**
925
 * Returns an FiniteIterableInterface, providing a fluent interface to itertools
926
 *
927
 * > iterable([1, 2, 3])->filter(...)->map(...)->first(...)
928
 *
929
 * @param array|string|\Iterator $iterable
930
 * @return FiniteIterableInterface
931
 */
932
function iterable($iterable)
933
{
934 419
    if ($iterable instanceof FiniteIterableInterface) {
935 2
        return $iterable;
936
    }
937
938 419
    return new IterableIterator(conversions\mixed_to_iterator($iterable));
939
}
940