Test Setup Failed
Pull Request — master (#49)
by
unknown
07:27
created

itertools.php ➔ collapse()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 7
ccs 0
cts 0
cp 0
crap 6
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 16
{
122 15
    if (!($iterable instanceof AccumulateInterface)) {
123
        $iterable = iterable($iterable);
124
    }
125 14
126
    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 17
{
151 17
    if (!($iterable instanceof ReduceInterface)) {
152
        $iterable = iterable($iterable);
153
    }
154 14
155
    return $iterable->reduce($closure, $initializer);
156
}
157
158
function collapse($iterable) {
159
    if (!($iterable instanceof CollapseInterface)) {
160
        $iterable = iterable($iterable);
161
    }
162
163
    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 12
 *
180 12
 * @return ChainIterator
181 11
 */
182 11
function chain()
183
{
184 1
    // note, once we stop supporting php 5.5, we can rewrite the code below
185 1
    // 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
        list($iterable) = array_slice($args, 0, 1);
191
        $iterables = array_slice($args, 1);
192 9
    } else {
193
        $iterable = null;
194
        $iterables = [];
195
    }
196
197
    if (!($iterable instanceof ChainInterface)) {
198
        $iterable = iterable($iterable);
199
    }
200
201
    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 36
 * > count(2.5, 0.5)
212 3
 * 2.5 3.0 3.5 4.0 ...
213
 *
214
 * @param int|float $start
215 33
 * @param int|float $step
216 3
 * @return CountIterator
217
 */
218
function count($start = 0, $step = 1)
219 30
{
220
    if (!(is_int($start) || is_float($start))) {
221
        throw new \InvalidArgumentException('Argument $start must be an integer or float');
222
    }
223
224
    if (!(is_int($step) || is_float($step))) {
225
        throw new \InvalidArgumentException('Argument $step must be an integer or float');
226
    }
227
228
    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 12
 *
236 12
 * > cycle('ABCD')
237
 * A B C D A B C D A B C D ...
238
 *
239 9
 * @param array|string|\Iterator $iterable
240
 * @return CycleIterator
241
 */
242
function cycle($iterable)
243
{
244
    if (!($iterable instanceof CycleInterface)) {
245
        $iterable = iterable($iterable);
246
    }
247
248
    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 23
 * @param null|string|\Closure $strategy
274 23
 * @param array|string|\Iterator $iterable
275
 * @return MapByIterator
276
 */
277 23
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
    if (!($iterable instanceof MapByInterface)) {
283
        $iterable = iterable($iterable);
284
    }
285
286
    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 32
 * @param array|string|\Iterator $iterable Additional $iterable parameters may follow
344 10
 * @return MapIterator
345
 */
346 22 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 32
    // to the map(...$iterables) structure.
350 31
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
351
352
    if (func_num_args() > 2) {
353 32
        $iterables = array_slice(func_get_args(), 2);
354
    } else {
355
        $iterables = [];
356
    }
357
358
    if (!($iterable instanceof ChainInterface)) {
359
        $iterable = iterable($iterable);
360
    }
361
362
    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 9
 * > repeat(10, 3)
400 4
 * 10 10 10
401
 *
402
 * @param mixed $mixed
403 5
 * @param null|int $times
404
 * @return RepeatIterator
405
 */
406
function repeat($mixed, $times = null)
407
{
408
    if (!(is_null($times) || (is_int($times) && $times >= 0))) {
409
        throw new \InvalidArgumentException('Argument $times must be null or a positive integer');
410
    }
411
412
    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 16
 * 'A'=>[['type'=>'A', 'title'=>'one'], ['type'=>'A', 'title'=>'two']] 'B'=>[['type'=>'B', 'title'=>'three']]
446 16
 *
447
 * @param null|string|\Closure $strategy
448
 * @param array|string|\Iterator $iterable
449 16
 * @param boolean $sort
450
 * @return GroupbyIterator
451
 */
452
function group_by($strategy, $iterable, $sort = true)
453
{
454
    if (!($iterable instanceof GroupByInterface)) {
455
        $iterable = iterable($iterable);
456
    }
457
458
    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 22
 * ['type'=>'A', 'title'=>'first'] ['type'=>'B', 'title'=>'second']] ['type'=>'C', 'title'=>'third']
498 21
 *
499
 * @param null|string|\Closure $strategy
500
 * @param array|string|\Iterator $iterable
501 22
 * @param boolean $reverse
502
 * @return SortedIterator
503
 */
504
function sorted($strategy, $iterable, $reverse = false)
505
{
506
    if (!($iterable instanceof SortedInterface)) {
507
        $iterable = iterable($iterable);
508
    }
509
510
    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 9
 *
523 9
 * @return FilterIterator
524 9
 */
525 3 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 3
{
527 3
    // note, once we stop supporting php 5.5, we can rewrite the code below
528
    // to the filter(...$iterables) structure.
529 6
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
530 5
531 5
    $args = func_get_args();
532 5
    switch (sizeof($args)) {
533
        case 1:
534
            $strategy = null;
535 1
            $iterable = $args[0];
536
            break;
537
538 8
        case 2:
539 7
            $strategy = $args[0];
540
            $iterable = $args[1];
541
            break;
542 5
543
        default:
544
            throw new \InvalidArgumentException('filter requires either one (iterable) or two (strategy, iterable) arguments');
545
    }
546
547
    if (!($iterable instanceof FilterInterface)) {
548
        $iterable = iterable($iterable);
549
    }
550
551
    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 11
 * @param array|string|\Iterator $iterable Additional $iterable parameters may follow
619 6
 * @return ZipIterator
620
 */
621 5 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 11
    // to the zip(...$iterables) structure.
625 11
    // http://php.net/manual/en/functions.arguments.php#functions.variable-arg-list
626
627
    if (func_num_args() > 1) {
628 8
        $iterables = array_slice(func_get_args(), 1);
629
    } else {
630
        $iterables = [];
631
    }
632
633
    if (!($iterable instanceof ZipInterface)) {
634
        $iterable = iterable($iterable);
635
    }
636
637
    return call_user_func_array([$iterable, 'zip'], $iterables);
638
}
639 6
640 5
/**
641
 * Returns an iterable with all the elements from $iterable reversed
642
 *
643 3
 * @param array|string|\Iterator $iterable
644
 * @return ReversedIterator
645
 */
646
function reversed($iterable)
647
{
648
    if (!($iterable instanceof ReversedInterface)) {
649
        $iterable = iterable($iterable);
650
    }
651
652
    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 25
 * 1 2 3
668 25
 *
669 25
 * > unique('id', [['id' => 1, 'value' => 'a'], ['id' => 1, 'value' => 'b']])
670 8
 * ['id' => 1, 'value' => 'a']  # one element in this list
671 8
 *
672 8
 * @return UniqueIterator
673
 */
674 17 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 15
{
676 15
    $args = func_get_args();
677 15
    switch (sizeof($args)) {
678
        case 1:
679
            $strategy = null;
680 2
            $iterable = $args[0];
681
            break;
682
683 23
        case 2:
684 23
            $strategy = $args[0];
685
            $iterable = $args[1];
686
            break;
687 17
688
        default:
689
            throw new \InvalidArgumentException('unique requires either one (iterable) or two (strategy, iterable) arguments');
690
    }
691
692
    if (!($iterable instanceof UniqueInterface)) {
693
        $iterable = iterable($iterable);
694
    }
695
696
    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 19
 * false
727 19
 *
728 19
 * > any([1, null, 3])
729 9
 * true
730 9
 *
731 9
 * @return boolean
732
 */
733 10 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 8
{
735 8
    $args = func_get_args();
736 8
    switch (sizeof($args)) {
737
        case 1:
738
            $strategy = null;
739 2
            $iterable = $args[0];
740
            break;
741
742 17
        case 2:
743 17
            $strategy = $args[0];
744
            $iterable = $args[1];
745
            break;
746 14
747
        default:
748
            throw new \InvalidArgumentException('any requires either one (iterable) or two (strategy, iterable) arguments');
749
    }
750
751
    if (!($iterable instanceof AllInterface)) {
752
        $iterable = iterable($iterable);
753
    }
754
755
    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 19
 * true
772 19
 *
773 19
 * > all([1, null, 3])
774 9
 * false
775 9
 *
776 9
 * @return boolean
777
 */
778 10 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 8
{
780 8
    $args = func_get_args();
781 8
    switch (sizeof($args)) {
782
        case 1:
783
            $strategy = null;
784 2
            $iterable = $args[0];
785
            break;
786
787 17
        case 2:
788 17
            $strategy = $args[0];
789
            $iterable = $args[1];
790
            break;
791 14
792
        default:
793
            throw new \InvalidArgumentException('all requires either one (iterable) or two (strategy, iterable) arguments');
794
    }
795
796
    if (!($iterable instanceof AllInterface)) {
797
        $iterable = iterable($iterable);
798
    }
799
800
    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 27
 * 'b', 'c', 'd'
821 27
 *
822
 * @param array|string|\Iterator $iterable
823
 * @param integer $start
824 27
 * @param null|integer $end
825
 * @return SliceIterator
826
 */
827
function slice($iterable, $start, $end = null)
828
{
829
    if (!($iterable instanceof SliceInterface)) {
830
        $iterable = iterable($iterable);
831
    }
832
833
    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 9
 * > first([])
843 9
 * null
844
 *
845
 * @param array|string|\Iterator $iterable
846 5
 * @param mixed $default
847
 * @return mixed
848
 */
849
function first($iterable, $default = null)
850
{
851
    if (!($iterable instanceof FirstInterface)) {
852
        $iterable = iterable($iterable);
853
    }
854
855
    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 5
 * > first_key([])
865 5
 * null
866
 *
867
 * @param array|string|\Iterator $iterable
868 5
 * @param mixed $default
869
 * @return mixed
870
 */
871
function first_key($iterable, $default = null)
872
{
873
    if (!($iterable instanceof FirstInterface)) {
874
        $iterable = iterable($iterable);
875
    }
876
877
    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 9
 * > last([])
887 9
 * null
888
 *
889
 * @param array|string|\Iterator $iterable
890 5
 * @param mixed $default
891
 * @return mixed
892
 */
893
function last($iterable, $default = null)
894
{
895
    if (!($iterable instanceof LastInterface)) {
896
        $iterable = iterable($iterable);
897
    }
898
899
    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 5
 * > last_key([])
909 5
 * null
910
 *
911
 * @param array|string|\Iterator $iterable
912 5
 * @param mixed $default
913
 * @return mixed
914
 */
915
function last_key($iterable, $default = null)
916
{
917
    if (!($iterable instanceof LastInterface)) {
918
        $iterable = iterable($iterable);
919
    }
920
921
    return $iterable->lastKey($default);
922
}
923
924
/**
925 413
 * Returns an FiniteIterableInterface, providing a fluent interface to itertools
926 2
 *
927
 * > iterable([1, 2, 3])->filter(...)->map(...)->first(...)
928
 *
929 413
 * @param array|string|\Iterator $iterable
930
 * @return FiniteIterableInterface
931
 */
932
function iterable($iterable)
933
{
934
    if ($iterable instanceof FiniteIterableInterface) {
935
        return $iterable;
936
    }
937
938
    return new IterableIterator(conversions\mixed_to_iterator($iterable));
939
}
940