GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#5)
by t
63:46
created

Arrays::lists()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 9
c 1
b 0
f 0
nc 8
nop 3
dl 0
loc 13
rs 9.9666
1
<?php
2
/**
3
 * Class Arrays
4
 *
5
 * @link https://www.icy2003.com/
6
 * @author icy2003 <[email protected]>
7
 * @copyright Copyright (c) 2017, icy2003
8
 */
9
10
namespace icy2003\php\ihelpers;
11
12
use icy2003\php\I;
13
use LogicException;
14
15
/**
16
 * 数组类
17
 *
18
 * 常见数组格式的拼装和处理
19
 */
20
class Arrays
21
{
22
23
    use ArraysTrait;
24
25
    /**
26
     * 以各个元素的某字段值作为键重新指回该元素,此值对于该元素需唯一
27
     *
28
     * @param array  $array
29
     * @param string $index 用来作为键的某字段
30
     * @param boolean $isMerge 是否合并相同键的项到数组,默认否(也就是后者覆盖前者)
31
     *
32
     * @return array
33
     *
34
     * @test icy2003\php_tests\ihelpers\ArraysTest::testIndexBy
35
     */
36
    public static function indexBy($array, $index, $isMerge = false)
37
    {
38
        $result = [];
39
        foreach ($array as $row) {
40
            if (!array_key_exists($index, $row)) {
41
                return [];
42
            }
43
            if (false === $isMerge) {
44
                $result[$row[$index]] = $row;
45
            } else {
46
                $result[$row[$index]][] = $row;
47
            }
48
        }
49
50
        return $result;
51
    }
52
53
    /**
54
     * 选取数组中指定键的某几列
55
     *
56
     * - 简单理解就是:从数据库里查出来几条数据,只拿其中的几个属性
57
     * - 当 $dimension 为 2 时,理解为从几条数据里拿属性
58
     * - 当 $dimension 为 1 时,理解为从一条数据里拿属性
59
     *
60
     * @param array $array
61
     * @param array $keys 某几项字段,支持 I::get 的键格式,如果给 null,则返回原数组
62
     * @param integer $dimension 维度,只能为 1 或 2,默认 2,表示处理二维数组
63
     *
64
     * @return array
65
     *
66
     * @test icy2003\php_tests\ihelpers\ArraysTest::testColumns
67
     */
68
    public static function columns($array, $keys = null, $dimension = 2)
69
    {
70
        if (null === $keys) {
71
            return $array;
72
        }
73
        $result = [];
74
        if (2 === $dimension) {
75
            foreach ($array as $k => $row) {
76
                foreach ($keys as $key) {
77
                    if (array_key_exists($key, $row)) {
78
                        $result[$k][$key] = I::get($row, $key);
79
                    } else {
80
                        $result[$k][$key] = null;
81
                    }
82
                }
83
            }
84
        }
85
        if (1 === $dimension) {
86
            foreach ($array as $k => $row) {
87
                if (in_array($k, $keys, true)) {
88
                    $result[$k] = $row;
89
                } else {
90
                    $result[$k] = null;
91
                }
92
            }
93
        }
94
95
        return $result;
96
    }
97
98
    /**
99
     * 返回二维(或者更高)数组中指定键的一列的所有值
100
     *
101
     * - array_column 要求 PHP >= 5.5,这个是兼容 5.5 以下的
102
     * - 如果需要取某几项,使用 Arrays::columns
103
     * - 简单理解就是:从数据库里查出来几条数据,只要其中某个属性的所有值
104
     *
105
     * @see http://php.net/array_column
106
     *
107
     * @param array $array
108
     * @param string $column 需要被取出来的字段
109
     * @param string $index 作为 index 的字段
110
     *
111
     * @return array
112
     *
113
     * @test icy2003\php_tests\ihelpers\ArraysTest::testColumn
114
     */
115
    public static function column($array, $column, $index = null)
116
    {
117
        if (function_exists('array_column')) {
118
            return array_column($array, $column, $index);
119
        } else {
120
            $result = [];
121
            foreach ($array as $row) {
122
                $data = I::get($row, $column);
123
                if (null === $index) {
124
                    $result[] = $data;
125
                } else {
126
                    $result[$row[$index]] = $data;
127
                }
128
            }
129
130
            return $result;
131
        }
132
    }
133
134
    /**
135
     * 创建一个数组,用一个数组的值作为其键名,另一个数组的值作为其值
136
     *
137
     * - array_combine:两个数组元素个数不一致将报错
138
     * - 在两个数组元素个数不一致时,以键为准:
139
     *      1.键比值多,值都被填充为 null
140
     *      2.值比键多,值被舍去
141
     * ```
142
     *
143
     * @see http://php.net/array_combine
144
     *
145
     * @param array $keys
146
     * @param array $values
147
     *
148
     * @return array
149
     */
150
    public static function combine($keys, $values)
151
    {
152
        if (count($keys) == count($values)) {
153
            return (array) array_combine($keys, $values);
154
        }
155
        $array = [];
156
        foreach ($keys as $index => $key) {
157
            $array[$key] = I::get($values, $index);
158
        }
159
        return $array;
160
    }
161
162
    /**
163
     * 递归地合并多个数组
164
     *
165
     * - array_merge_recursive:如果有相同的键,后者会覆盖前者
166
     * - 此函数会合并两个相同键的值到一个数组里
167
     *
168
     * @see http://php.net/array_merge_recursive
169
     *
170
     * @param array $a 数组1
171
     * @param array $b 数组2(可以任意个数组)
172
     *
173
     * @return array
174
     *
175
     * @test icy2003\php_tests\ihelpers\ArraysTest::testMerge
176
     */
177
    public static function merge($a, $b)
178
    {
179
        $args = func_get_args();
180
        $res = array_shift($args);
181
        while (!empty($args)) {
182
            foreach (array_shift($args) as $k => $v) {
183
                if (is_int($k)) {
184
                    if (array_key_exists($k, $res)) {
185
                        $res[] = $v;
186
                    } else {
187
                        $res[$k] = $v;
188
                    }
189
                } elseif (is_array($v) && isset($res[$k]) && is_array($res[$k])) {
190
                    $res[$k] = self::merge($res[$k], $v);
191
                } else {
192
                    $res[$k] = $v;
193
                }
194
            }
195
        }
196
197
        return $res;
198
    }
199
200
    /**
201
     *  range 的性能优化版
202
     *
203
     * @see http://php.net/manual/zh/language.generators.overview.php
204
     * @version PHP >= 5.5
205
     *
206
     * @param integer $start 开始
207
     * @param integer $end 结束
208
     * @param integer $step 步长
209
     *
210
     * @return \Generator
211
     * @throws \LogicException
212
     *
213
     * @test icy2003\php_tests\ihelpers\ArraysTest::testRangeGenerator
214
     */
215
    public static function rangeGenerator($start, $end, $step = 1)
216
    {
217
        if ($start < $end) {
218
            if ($step <= 0) {
219
                throw new LogicException('步长必须大于 0');
220
            }
221
            for ($i = $start; $i <= $end; $i += $step) {
222
                yield $i;
223
            }
224
        } elseif ($start > $end) {
225
            if ($step >= 0) {
226
                throw new LogicException('步长必须小于 0');
227
            }
228
            for ($i = $start; $i >= $end; $i += $step) {
229
                yield $i;
230
            }
231
        } else {
232
            yield $start;
233
        }
234
    }
235
236
    /**
237
     * 找到符合条件的第一项
238
     *
239
     * @param array $array
240
     * @param callback $callback 条件回调,结果为 true 的第一项会被取出
241
     *
242
     * @return mixed
243
     *
244
     * @test icy2003\php_tests\ihelpers\ArraysTest::testDetectFirst
245
     */
246
    public static function detectFirst($array, $callback)
247
    {
248
        foreach ($array as $key => $item) {
249
            if (true === I::trigger($callback, [$item, $key])) {
250
                return $item;
251
            }
252
        }
253
        return null;
254
    }
255
256
    /**
257
     * 找到符合条件的所有项
258
     *
259
     * @param array $array
260
     * @param callback $callback 条件回调,结果为 true 的所有项会被取出
261
     * @param callback $filter 对符合条件的项进行回调处理并返回
262
     *
263
     * @return array
264
     *
265
     * @test icy2003\php_tests\ihelpers\ArraysTest::testDetectAll
266
     */
267
    public static function detectAll($array, $callback, $filter = null)
268
    {
269
        $all = [];
270
        foreach ($array as $key => $item) {
271
            if (true === I::trigger($callback, [$item, $key])) {
272
                if (null !== $filter) {
273
                    $all[$key] = I::trigger($filter, [$item, $key]);
274
                } else {
275
                    $all[$key] = $item;
276
                }
277
            }
278
        }
279
        return $all;
280
    }
281
282
    /**
283
     * 返回数组的最后一个元素的键
284
     *
285
     * - array_key_last:需要 PHP7.3.0+ 才能支持
286
     *
287
     * @param array $array
288
     *
289
     * @return string
290
     *
291
     * @test icy2003\php_tests\ihelpers\ArraysTest::testKeyLast
292
     */
293
    public static function keyLast($array)
294
    {
295
        if (!is_array($array) || empty($array)) {
296
            return null;
297
        }
298
        if (function_exists('array_key_last')) {
299
            return array_key_last($array);
300
        }
301
        end($array);
302
        return key($array);
303
    }
304
305
    /**
306
     * 返回数组的第一个元素的键
307
     *
308
     * - array_key_first:需要 PHP7.3.0+ 才能支持
309
     *
310
     * @param array $array
311
     *
312
     * @return string
313
     *
314
     * @test icy2003\php_tests\ihelpers\ArraysTest::testKeyFirst
315
     */
316
    public static function keyFirst($array)
317
    {
318
        if (!is_array($array) || empty($array)) {
319
            return null;
320
        }
321
        if (function_exists('array_key_first')) {
322
            return array_key_first($array);
323
        }
324
        reset($array);
325
        return key($array);
326
    }
327
328
    /**
329
     * 获取数组的维度
330
     *
331
     * @param array $array 多维数组
332
     *
333
     * @return int
334
     *
335
     * @test icy2003\php_tests\ihelpers\ArraysTest::testDimension
336
     */
337
    public static function dimension($array)
338
    {
339
        if (!is_array($array)) {
340
            return 0;
341
        }
342
        $max = 1;
343
        foreach ($array as $value) {
344
            if (is_array($value)) {
345
                $d = self::dimension($value) + 1;
346
                if ($d > $max) {
347
                    $max = $d;
348
                }
349
            }
350
        }
351
        return $max;
352
    }
353
354
    /**
355
     * 判断数组是不是关联数组
356
     *
357
     * @param array $array
358
     *
359
     * @return boolean
360
     *
361
     * @test icy2003\php_tests\ihelpers\ArraysTest::testIsAssoc
362
     */
363
    public static function isAssoc($array)
364
    {
365
        if (is_array($array)) {
366
            $keys = array_keys($array);
367
            return $keys !== array_keys($keys);
368
        }
369
        return false;
370
    }
371
372
    /**
373
     * 判断数组是不是索引数组
374
     *
375
     * 索引数组必须是下标从 0 开始的数组,键是数字还是字符串类型的数字无所谓
376
     *
377
     * @param array $array
378
     *
379
     * @return boolean
380
     *
381
     * @test icy2003\php_tests\ihelpers\ArraysTest::testIsIndexed
382
     */
383
    public static function isIndexed($array)
384
    {
385
        if (is_array($array)) {
386
            $keys = array_keys($array);
387
            return $keys === array_keys($keys);
388
        }
389
        return false;
390
    }
391
392
    /**
393
     * 返回数组的顺数第 n 个元素,其中 n >= 1 且为整数,空数组直接返回 null
394
     *
395
     * - 支持关联数组,超过数组长度会对数组长度求余后查找
396
     *
397
     * @param array $array
398
     * @param int $pos 顺数第 n 个,默认 1
399
     *
400
     * @return mixed
401
     *
402
     * @test icy2003\php_tests\ihelpers\ArraysTest::testFirst
403
     */
404
    public static function first($array, $pos = 1)
405
    {
406
        if (0 === ($count = self::count($array))) {
407
            return null;
408
        }
409
        $p = $pos % $count;
410
        if (0 === $p) {
411
            $p = $count;
412
        }
413
        for ($i = 1; $i < $p; $i++) {
414
            next($array);
415
        }
416
        return current($array);
417
    }
418
419
    /**
420
     * 返回数组的倒数第 n 个元素,其中 n >= 1 且为整数,空数组直接返回 null
421
     *
422
     * - 支持关联数组,超过数组长度会对数组长度求余后查找
423
     *
424
     * @param array $array
425
     * @param int $pos 倒数第 n 个,默认 1
426
     *
427
     * @return mixed
428
     *
429
     * @test icy2003\php_tests\ihelpers\ArraysTest::testLast
430
     */
431
    public static function last($array, $pos = 1)
432
    {
433
        if (0 === ($count = self::count($array))) {
434
            return null;
435
        }
436
        $p = $pos % $count;
437
        if (0 === $p) {
438
            $p = $count;
439
        }
440
        end($array);
441
        for ($i = 1; $i < $p; $i++) {
442
            prev($array);
443
        }
444
        return current($array);
445
    }
446
447
    /**
448
     * 计算数组中的单元数目
449
     *
450
     * - count:在非数组情况下,除了 null 会返回 0,其他都返回 1,囧
451
     * - $callback 参数用于对符合条件的项做筛选
452
     *
453
     * @param array $array 数组
454
     * @param callback|string $callback 回调,返回回调值为 true 的项,如果此参数是字符串,表示查询和此字符串严格相等的项
455
     * @param boolean $isStrict 是否为严格模式,如果为 false,回调值为 true 值的也会返回,为字符串时不使用严格比较
456
     *
457
     * @return integer
458
     */
459
    public static function count($array, $callback = null, $isStrict = true)
460
    {
461
        $count = 0;
462
        if (is_array($array)) {
0 ignored issues
show
introduced by
The condition is_array($array) is always true.
Loading history...
463
            if (null === $callback) {
464
                return count($array);
465
            } elseif (is_string($callback) || is_callable($callback)) {
466
                $function = $callback;
467
                if (is_string($callback)) {
468
                    $function = function ($row) use ($callback, $isStrict) {
469
                        return true === $isStrict ? $row === $callback : $row == $callback;
470
                    };
471
                }
472
                foreach ($array as $key => $row) {
473
                    if (true === I::trigger($function, [$row, $key])) {
474
                        $count++;
475
                    }
476
                }
477
478
            }
479
        }
480
        return $count;
481
    }
482
483
    /**
484
     * 返回指定长度的数组,不足的值设置为 null
485
     *
486
     * @param array $array
487
     * @param integer $count 指定长度
488
     * @param callback $callback 回调参数:数组的值、数组的键
489
     *
490
     * @return array
491
     */
492
    public static function lists($array, $count = null, $callback = null)
493
    {
494
        null === $count && $count = self::count($array);
495
        $arrayCount = self::count($array);
496
        if ($arrayCount >= $count) {
497
            $return = $array;
498
        } else {
499
            $return = self::merge($array, self::fill(0, $count - $arrayCount, null));
500
        }
501
        if (null !== $callback) {
502
            $return = array_map($callback, array_values($return), array_keys($return));
503
        }
504
        return $return;
505
    }
506
507
}
508