Completed
Push — master ( 2a9e3e...dd1f5f )
by Daniel
41:35 queued 32:48
created

Transform::pop()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 18
Code Lines 9

Duplication

Lines 7
Ratio 38.89 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 7
loc 18
rs 9.2
cc 4
eloc 9
nc 5
nop 2
1
<?php
2
namespace Narrowspark\Arr;
3
4
use Narrowspark\Arr\Traits\SplitPathTrait;
5
use Narrowspark\Arr\Traits\ValueTrait;
6
7
class Transform
8
{
9
    /**
10
     * Dotted array cache.
11
     *
12
     * @var array
13
     */
14
    protected $dotted = [];
15
16
    /**
17
     * A instance of Access
18
     *
19
     * @var \Narrowspark\Arr\Access
20
     */
21
    protected $access;
22
23
    /**
24
     * A instance of Access
25
     *
26
     * @var \Narrowspark\Arr\Enumerator
27
     */
28
    protected $enumerator;
29
30
    public function __construct()
31
    {
32
        $this->access     = new Access();
33
        $this->enumerator = new Enumerator();
34
    }
35
36
    /**
37
     * Pop value from sub array.
38
     *
39
     * @param array  $array
40
     * @param string $key
41
     *
42
     * @return mixed
43
     */
44
    public static function pop(array $array, $key)
45
    {
46
        $keys = explode('.', $key);
47
48 View Code Duplication
        foreach ($keys as $key) {
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...
49
            if (!isset($array[$key])) {
50
                return null;
51
            }
52
53
            $array = $array[$key];
54
        }
55
56
        if (!is_array($array)) {
57
            return null;
58
        }
59
60
        return array_pop($array);
61
    }
62
63
    /**
64
     * Swap two elements between positions.
65
     *
66
     * @param array  $array array to swap
67
     * @param string $swapA
68
     * @param string $swapB
69
     *
70
     * @return array|null
71
     */
72
    public function swap(array $array, $swapA, $swapB)
73
    {
74
        list($array[$swapA], $array[$swapB]) = [$array[$swapB], $array[$swapA]];
75
76
        return $array;
77
    }
78
79
    /**
80
     * Create a new array consisting of every n-th element.
81
     *
82
     * @param array $array
83
     * @param int   $step
84
     * @param int   $offset
85
     *
86
     * @return array
87
     */
88
    public static function every($array, $step, $offset = 0)
89
    {
90
        $new = [];
91
92
        $position = 0;
93
94
        foreach ($array as $key => $item) {
95
            if ($position % $step === $offset) {
96
                $new[] = $item;
97
            }
98
99
            $position++;
100
        }
101
102
        return $new;
103
    }
104
105
    /**
106
     * Indexes an array depending on the values it contains.
107
     *
108
     * @param array    $array
109
     * @param callable $callback  Function to combine values.
110
     * @param bool     $overwrite Should duplicate keys be overwritten?
111
     *
112
     * @return array Indexed values.
113
     */
114
    public function combine(array $array, callable $callback, $overwrite = true)
115
    {
116
        $combined = [];
117
118
        foreach ($array as $key => $value) {
119
            $combinator = call_user_func($callback, $value, $key);
120
            $index      = $combinator->key();
121
122
            if ($overwrite || !isset($combined[$index])) {
123
                $combined[$index] = $combinator->current();
124
            }
125
        }
126
127
        return $combined;
128
    }
129
130
    /**
131
     * Collapse an array of arrays into a single array.
132
     *
133
     * @param array $array
134
     *
135
     * @return array
136
     */
137
    public function collapse(array $array)
138
    {
139
        $results = [];
140
141
        foreach ($array as $values) {
142
            if (!is_array($values)) {
143
                continue;
144
            }
145
146
            $results = array_merge($results, $values);
147
        }
148
149
        return $results;
150
    }
151
152
    /**
153
     * Divide an array into two arrays. One with keys and the other with values.
154
     *
155
     * @param array $array
156
     *
157
     * @return array[]
158
     */
159
    public function divide($array)
160
    {
161
        return [array_keys($array), array_values($array)];
162
    }
163
164
    /**
165
     * Reindexes a list of values.
166
     *
167
     * @param array $array
168
     * @param array $map          An map of correspondances of the form
169
     *                            ['currentIndex' => 'newIndex'].
170
     * @param bool  $keepUnmapped Whether or not to keep keys that are not
171
     *                            remapped.
172
     *
173
     * @return array
174
     */
175
    public function reindex(array $array, array $map, $keepUnmapped = true)
176
    {
177
        $reindexed = $keepUnmapped
178
            ? $array
179
            : [];
180
181
        foreach ($map as $from => $to) {
182
            if (isset($array[$from])) {
183
                $reindexed[$to] = $array[$from];
184
            }
185
        }
186
187
        return $reindexed;
188
    }
189
190
    /**
191
     * Merges two arrays recursively.
192
     *
193
     * @param array $first  Original data.
194
     * @param array $second Data to be merged.
195
     *
196
     * @return array
197
     */
198
    public function merge(array $first, array $second)
199
    {
200
        foreach ($second as $key => $value) {
201
            $shouldBeMerged = (
202
                isset($first[$key])
203
                && is_array($first[$key])
204
                && is_array($value)
205
            );
206
207
            $first[$key] = $shouldBeMerged
208
                ? $this->merge($first[$key], $value)
209
                : $value;
210
        }
211
212
        return $first;
213
    }
214
215
    /**
216
     * Extend one array with another.
217
     *
218
     * @param array $arrays
219
     *
220
     * @return array
221
     */
222
    public function extend(array $arrays)
223
    {
224
        $merged = [];
225
226
        foreach (func_get_args() as $array) {
227
            foreach ($array as $key => $value) {
228
                if (is_array($value) && $this->access->has($merged, $key) && is_array($merged[$key])) {
229
                    $merged[$key] = $this->extend($merged[$key], $value);
230
                } else {
231
                    $merged[$key] = $value;
232
                }
233
            }
234
        }
235
236
        return $merged;
237
    }
238
239
    /**
240
     * Transforms a 1-dimensional array into a multi-dimensional one,
241
     * exploding keys according to a separator.
242
     *
243
     * @param array $array
244
     *
245
     * @return array
246
     */
247
    public function asHierarchy(array $array)
248
    {
249
        $hierarchy = [];
250
251
        foreach ($array as $key => $value) {
252
            $segments     = explode('.', $key);
253
            $valueSegment = array_pop($segments);
254
            $branch       = &$hierarchy;
255
256
            foreach ($segments as $segment) {
257
                if (!isset($branch[$segment])) {
258
                    $branch[$segment] = [];
259
                }
260
261
                $branch = &$branch[$segment];
262
            }
263
264
            $branch[$valueSegment] = $value;
265
        }
266
267
        return $hierarchy;
268
    }
269
270
    /**
271
     * Separates elements from an array into groups.
272
     * The function maps an element to the key that will be used for grouping.
273
     * If no function is passed, the element itself will be used as key.
274
     *
275
     * @param array         $array
276
     * @param callable|null $callback
277
     *
278
     * @return array
279
     */
280
    public function groupBy(array $array, callable $callback = null)
281
    {
282
        $callback = $callback ?: function ($value) {
283
            return $value;
284
        };
285
286
        return array_reduce(
287
            $array,
288
            function ($buckets, $value) use ($callback) {
289
                $key = call_user_func($callback, $value);
290
291
                if (!array_key_exists($key, $buckets)) {
292
                    $buckets[$key] = [];
293
                }
294
295
                $buckets[$key][] = $value;
296
297
                return $buckets;
298
            },
299
            []
300
        );
301
    }
302
303
    /**
304
     * Flatten a multi-dimensional associative array with dots.
305
     *
306
     * @param array  $array
307
     * @param string $prepend
308
     *
309
     * @return array
310
     */
311
    public function dot($array, $prepend = '')
312
    {
313
        $cache = serialize(['array' => $array, 'prepend' => $prepend]);
314
315
        if (array_key_exists($cache, $this->dotted)) {
316
            return $this->dotted[$cache];
317
        }
318
319
        $results = [];
320
321 View Code Duplication
        foreach ($array as $key => $value) {
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...
322
            if (is_array($value)) {
323
                $results = array_merge($results, $this->dot($value, $prepend . $key . '.'));
324
            } else {
325
                $results[$prepend . $key] = $value;
326
            }
327
        }
328
329
        return $this->dotted[$cache] = $results;
330
    }
331
332
    /**
333
     * Flatten a nested array to a separated key.
334
     *
335
     * @param array       $array
336
     * @param string|null $separator
337
     * @param string      $prepend
338
     *
339
     * @return array
340
     */
341
    public function flatten(array $array, $separator = null, $prepend = '')
342
    {
343
        $flattened = [];
344
345 View Code Duplication
        foreach ($array as $key => $value) {
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...
346
            if (is_array($value)) {
347
                $flattened = array_merge($flattened, $this->flatten($value, $separator, $prepend . $key . $separator));
348
            } else {
349
                $flattened[$prepend . $key] = $value;
350
            }
351
        }
352
353
        return $flattened;
354
    }
355
356
    /**
357
     * Expand a flattened array with dots to a multi-dimensional associative array.
358
     *
359
     * @param array  $array
360
     * @param string $prepend
361
     *
362
     * @return array
363
     */
364
    public function expand(array $array, $prepend = '')
365
    {
366
        $results = [];
367
368
        if ($prepend) {
369
            $prepend .= '.';
370
        }
371
372
        foreach ($array as $key => $value) {
373
            if ($prepend) {
374
                $pos = strpos($key, $prepend);
375
376
                if ($pos === 0) {
377
                    $key = substr($key, strlen($prepend));
378
                }
379
            }
380
381
            $results = $this->access->set($results, $key, $value);
382
        }
383
384
        return $results;
385
    }
386
387
    /**
388
     * Reset all numerical indexes of an array (start from zero).
389
     * Non-numerical indexes will stay untouched. Returns a new array.
390
     *
391
     * @param array      $array
392
     * @param bool|false $deep
393
     *
394
     * @return array
395
     */
396
    public function reset(array $array, $deep = false)
397
    {
398
        $target = [];
399
400
        foreach ($array as $key => $value) {
401
            if ($deep && is_array($value)) {
402
                $value = $this->reset($value);
403
            }
404
405
            if (is_numeric($key)) {
406
                $target[] = $value;
407
            } else {
408
                $target[$key] = $value;
409
            }
410
        }
411
412
        return $target;
413
    }
414
415
    /**
416
     * Extend one array with another. Non associative arrays will not be merged
417
     * but rather replaced.
418
     *
419
     * @param array $arrays
420
     *
421
     * @return array
422
     */
423
    public function extendDistinct(array $arrays)
0 ignored issues
show
Unused Code introduced by
The parameter $arrays is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
424
    {
425
        $merged     = [];
426
427
        foreach (func_get_args() as $array) {
428
            foreach ($array as $key => $value) {
429
                if (is_array($value) && $this->access->has($merged, $key) && is_array($merged[$key])) {
430
                    if ($this->enumerator->isAssoc($value) && $this->enumerator->isAssoc($merged[$key])) {
431
                        $merged[$key] = $this->extendDistinct($merged[$key], $value);
432
433
                        continue;
434
                    }
435
                }
436
437
                $merged[$key] = $value;
438
            }
439
        }
440
441
        return $merged;
442
    }
443
444
    /**
445
     * Recursively sort an array by keys and values.
446
     *
447
     * @param array $array
448
     *
449
     * @return array
450
     */
451
    public function sortRecursive(array $array)
452
    {
453
        foreach ($array as &$value) {
454
            if (is_array($value)) {
455
                $value = $this->sortRecursive($value);
456
            }
457
        }
458
459
        // sort associative array
460
        if ($this->enumerator->isAssoc($array)) {
461
            ksort($array);
462
            // sort regular array
463
        } else {
464
            sort($array);
465
        }
466
467
        return $array;
468
    }
469
470
    /**
471
     * Will turn each element in $arr into an array then appending
472
     * the associated indexs from the other arrays into this array as well.
473
     *
474
     * @param array $array
475
     * @param array $arrays
476
     *
477
     * @return array
478
     */
479
    public function zip(array $array, array $arrays)
0 ignored issues
show
Unused Code introduced by
The parameter $arrays is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
480
    {
481
        $args = func_get_args();
482
        array_shift($args);
483
484
        foreach ($array as $key => $value) {
485
            $array[$key] = [$value];
486
487
            foreach ($args as $k => $v) {
488
                $array[$key][] = current($args[$k]);
489
490
                if (next($args[$k]) === false && $args[$k] !== [null]) {
491
                    $args[$k] = [null];
492
                }
493
            }
494
        }
495
496
        return $array;
497
    }
498
}
499