Completed
Push — master ( b139e2...07b7da )
by Daniel
03:29
created

Transform::reset()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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