Passed
Push — version-4 ( db79e6...123e06 )
by Sebastian
02:21
created

ArrayListTrait::flatten()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 7
ccs 5
cts 5
cp 1
crap 1
rs 10
1
<?php
2
declare(strict_types=1);
3
/*
4
 * Copyright (C) 2018 Sebastian Böttger <[email protected]>
5
 * You may use, distribute and modify this code under the
6
 * terms of the MIT license.
7
 *
8
 * You should have received a copy of the MIT license with
9
 * this file. If not, please visit: https://opensource.org/licenses/mit-license.php
10
 */
11
12
namespace Seboettg\Collection\Lists;
13
14
use Seboettg\Collection\Comparable\Comparable;
15
use Seboettg\Collection\Lists\ListFeatures\ListAccessTrait;
16
use Seboettg\Collection\Lists\MapFeatures\MapFeaturesTrait;
17
use Seboettg\Collection\Map\MapInterface;
18
use Seboettg\Collection\NativePhp\IteratorTrait;
19
use function Seboettg\Collection\Assert\assertComparable;
20
use function Seboettg\Collection\Assert\assertStringable;
21
use function Seboettg\Collection\Map\mapOf;
22
use function Seboettg\Collection\Map\pair;
23
24
/**
25
 * @property array $array Base array of this data structure
26
 */
27
trait ArrayListTrait
28
{
29
    use ListAccessTrait;
30
    use IteratorTrait;
31
    use MapFeaturesTrait;
32
33
    /**
34
     * flush array list
35
     *
36
     * @return ListInterface|ArrayListTrait
37
     */
38 1
    public function clear(): void
39
    {
40 1
        unset($this->array);
41 1
        $this->array = [];
42 1
    }
43
44
    /**
45
     * Adds the specified element to the end of this list.
46
     *
47
     * @param mixed $element
48
     */
49 16
    public function add($element): void
50
    {
51 16
        end($this->array);
52 16
        $this->array[] = $element;
53 16
    }
54
55
    /**
56
     * @inheritDoc
57
     */
58 1
    public function addAll(iterable $elements): void
59
    {
60 1
        foreach ($elements as $element) {
61 1
            $this->add($element);
62
        }
63 1
    }
64
65
    /**
66
     * @param $key
67
     * @return ListInterface|ArrayListTrait
68
     */
69 1
    public function remove($key): ListInterface
70
    {
71 1
        unset($this->array[$key]);
72 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Seboettg\Collection\Lists\ArrayListTrait which is incompatible with the type-hinted return Seboettg\Collection\Lists\ListInterface.
Loading history...
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78 5
    public function contains($value): bool
79
    {
80 5
        if ((isScalarOrStringable($value) && $this->all(fn($item) => isScalarOrStringable($item)))) {
81 3
            return in_array($value, $this->array, true) !== false;
82
        }
83 2
        if (isComparable($value) && $this->all(fn($item) => isComparable($item))) {
84 1
            $items = $this->array;
85
            /** @var Comparable $value */
86
            /** @var Comparable $item */
87 1
            foreach ($items as $item) {
88 1
                if ($item->compareTo($value) === 0) {
89 1
                    return true;
90
                }
91
            }
92
        } else {
93 1
            return in_array(spl_object_hash($value), array_map(fn($item) => spl_object_hash($item), $this->array), true);
94
        }
95 1
        return false;
96
    }
97
98
    /**
99
     * @inheritDoc
100
     * @see http://php.net/manual/en/function.shuffle.php
101
     * @return ListInterface
102
     */
103 1
    public function shuffle(): ListInterface
104
    {
105 1
        shuffle($this->array);
106 1
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Seboettg\Collection\Lists\ArrayListTrait which is incompatible with the type-hinted return Seboettg\Collection\Lists\ListInterface.
Loading history...
107
    }
108
109
    /**
110
     * @inheritDoc
111
     */
112 12
    public function filter(?callable $predicate = null, bool $preserveKeys = false): ListInterface
113
    {
114 12
        $list = emptyList();
115 12
        $filtered = $predicate == null ? array_filter($this->array) : array_filter($this->array, $predicate);
116 12
        $list->setArray(
117 12
            $preserveKeys ? $filtered : array_values($filtered)
118
        );
119 12
        return $list;
120
    }
121
122
    /**
123
     * @param array $array
124
     */
125 37
    public function setArray(array $array): void
126
    {
127 37
        $this->replace($array);
128 37
    }
129
130
    /**
131
     * @param array $data
132
     */
133 37
    public function replace(array $data): void
134
    {
135 37
        $this->array = $data;
136 37
    }
137
138
    /**
139
     * returns a new ArrayList containing all the elements of this ArrayList after applying the callback function to each one.
140
     * @param callable $mapFunction
141
     * @return ListInterface|ArrayListTrait
142
     */
143 7
    public function map(callable $mapFunction): ListInterface
144
    {
145 7
        $list = emptyList();
146 7
        foreach ($this as $value) {
147 7
            $list->add($mapFunction($value));
148
        }
149 6
        return $list;
150
    }
151
152
    /**
153
     * @inheritDoc
154
     * @param callable $mapFunction
155
     * @return ListInterface
156
     */
157 1
    public function mapNotNull(callable $mapFunction): ListInterface
158
    {
159 1
        $list = $this->map($mapFunction);
160 1
        return $list->filter();
161
    }
162
163
    /**
164
     * Returns a new ArrayList containing a one-dimensional array of all elements of this ArrayList. Keys are going lost.
165
     * @return ListInterface
166
     */
167 1
    public function flatten(): ListInterface
168
    {
169 1
        $flattenedArray = [];
170
        array_walk_recursive($this->array, function ($item) use (&$flattenedArray) {
171 1
            $flattenedArray[] = $item;
172 1
        });
173 1
        return listOf(...$flattenedArray);
174
    }
175
176
    /**
177
     * @inheritDoc
178
     * @param callable $collectFunction
179
     * @return mixed
180
     */
181 1
    public function collect(callable $collectFunction)
182
    {
183 1
        return $collectFunction($this->array);
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189 4
    public function joinToString(string $delimiter, string $prefix = null, string $suffix = null): string
190
    {
191
        $result = implode($delimiter, $this->map(function ($item) {
192 4
            assertStringable($item, "Elements in list must be convertible to string in order to use joinToString.");
193 3
            return strval($item);
194 4
        })->toArray());
195 3
        if ($prefix !== null) {
196
            $result = $prefix . $result;
197
        }
198 3
        if ($suffix !== null) {
199
            $result = $result . $suffix;
200
        }
201 3
        return $result;
202
    }
203
204
    /**
205
     * @inheritDoc
206
     * @deprecated use joinToString instead
207
     */
208 1
    public function collectToString(string $delimiter): string
209
    {
210 1
        return $this->joinToString($delimiter);
211
    }
212
213
    /**
214
     * @inheritDoc
215
     * @return int
216
     */
217 17
    public function count(): int
218
    {
219 17
        return count($this->array);
220
    }
221
222
    /**
223
     * @inheritDoc
224
     */
225
    public function size(): int
226
    {
227
        return $this->count();
228
    }
229
230
    /**
231
     * @inheritDoc
232
     */
233 2
    public function minus(iterable $values): ListInterface
234
    {
235 2
        if (!$values instanceof ListInterface) {
236
            $valuesList = emptyList();
237
            $valuesList->setArray(is_array($values) ?? $values->toArray());
0 ignored issues
show
Bug introduced by
It seems like is_array($values) ?? $values->toArray() can also be of type boolean; however, parameter $array of anonymous//src/Lists/Functions.php$0::setArray() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

237
            $valuesList->setArray(/** @scrutinizer ignore-type */ is_array($values) ?? $values->toArray());
Loading history...
238
        } else {
239 2
            $valuesList = $values;
240
        }
241 2
        $newInstance = emptyList();
242 2
        foreach ($this->array as $value) {
243 2
            if (!$valuesList->contains($value)) {
244 2
                $newInstance->add($value);
245
            }
246
        }
247 2
        return $newInstance;
248
    }
249
250
    /**
251
     * @inheritDoc
252
     */
253
    public function intersect(ListInterface $list): ListInterface
254
    {
255
        $newInstance = emptyList();
256
        $newInstance->setArray(array_intersect($this->array, $list->array));
0 ignored issues
show
Bug introduced by
Accessing array on the interface Seboettg\Collection\Lists\ListInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
257
        return $newInstance;
258
    }
259
260
    /**
261
     * @inheritDoc
262
     * @param callable $predicate - f(item: mixed) -> bool
263
     * @return MapInterface<string, ListInterface>
264
     */
265 1
    public function partition(callable $predicate): MapInterface
266
    {
267 1
        $first = listOf(...array_filter($this->array, $predicate));
268 1
        return mapOf(
269 1
            pair("first", $first),
270 1
            pair("second", $this->minus($first))
271
        );
272
    }
273
274
275
    public function plus(iterable $other): ListInterface
276
    {
277
        $list = listOf(...$this->array);
278
        $list->addAll($other);
279
        return $list;
280
    }
281
282
    public function union(ListInterface $other): ListInterface
283
    {
284
        return $this->plus($other);
285
    }
286
287
    public function subtract(ListInterface $other): ListInterface
288
    {
289
        $list = emptyList();
290
        foreach ($this->array as $element) {
291
            if (!$other->contains($element)) {
292
                $list->add($element);
293
            }
294
        }
295
        return $list;
296
    }
297
298 2
    public function any(callable $predicate): bool
299
    {
300 2
        return $this->filter($predicate)->count() > 0;
301
    }
302
303 6
    public function all(callable $predicate): bool
304
    {
305 6
        return $this->count() === $this->filter($predicate)->count();
306
    }
307
308
    /**
309
     * @inheritDoc
310
     */
311 1
    public function chunk(int $size): ListInterface
312
    {
313 1
        $listOfChunks = emptyList();
314 1
        $arrayChunks = array_chunk($this->array, $size);
315 1
        foreach ($arrayChunks as $arrayChunk) {
316 1
            $listOfChunks->add(listOf(...$arrayChunk));
317
        }
318 1
        return $listOfChunks;
319
    }
320
321 1
    public function distinct(): ListInterface
322
    {
323 1
        $this->forEach(fn($item) => assertComparable($item,
324 1
            sprintf(
325 1
                "Each item must be of type scalar or implement \Stringable or implement %s",
326 1
                Comparable::class
327
            )
328 1
        ));
329 1
        $newList = emptyList();
330 1
        if ($this->all(fn($item): bool => isScalarOrStringable($item))) {
331
            return listFromArray(array_unique($this->toArray()));
332
        } else {
333 1
            if ($this->all(fn($item): bool => isComparable($item))) {
334 1
                $values = $this->array;
335 1
                foreach ($values as $value) {
336 1
                    if (!$newList->contains($value)) {
337 1
                        $newList->add($value);
338
                    }
339
                }
340 1
                return $newList;
341
            }
342
        }
343
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Seboettg\Collection\Lists\ArrayListTrait which is incompatible with the type-hinted return Seboettg\Collection\Lists\ListInterface.
Loading history...
344
    }
345
346
    /**
347
     * @inheritDoc
348
     */
349 6
    public function forEach(callable $action): void
350
    {
351 6
        foreach ($this->array as $element) {
352 6
            $action($element);
353
        }
354 6
    }
355
356
    /**
357
     * @inheritDoc
358
     */
359
    public function getOrElse(int $index, callable $defaultValue)
360
    {
361
        if ($this->array[$index] !== null) {
362
            return $this->array[$index];
363
        }
364
        return $defaultValue();
365
    }
366
367
    /**
368
     * @inheritDoc
369
     * @param int $fromIndex
370
     * @param int $toIndex
371
     * @return ListInterface
372
     */
373
    public function subList(int $fromIndex, int $toIndex): ListInterface
374
    {
375
        $list = emptyList();
376
        for ($i = $fromIndex; $i < $toIndex; ++$i) {
377
            if (isset($this->array[$i])) {
378
                $list->add($this->array[$i]);
379
            }
380
        }
381
        return $list;
382
    }
383
384
    /**
385
     * Return first element of this list that matches the matchingCondition
386
     *
387
     * @param callable $matchingCondition
388
     * @return mixed|null
389
     */
390
    public function searchBy(callable $matchingCondition)
391
    {
392
        $list = listOf(...array_filter($this->array));
393
        return $list->filter($matchingCondition)->first();
394
    }
395
396
    public function isEmpty(): bool
397
    {
398
        return $this->count() === 0;
399
    }
400
401
    /**
402
     * {@inheritDoc}
403
     */
404 9
    public function toArray(): array
405
    {
406 9
        return $this->array;
407
    }
408
}
409