Passed
Push — master ( 9e9b54...8c04f5 )
by
unknown
38s
created

itertools.php ➔ reduce()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

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