Passed
Branch version-4 (8b03a3)
by Sebastian
02:18
created

ArrayListTrait::all()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
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\Map\MapInterface;
15
use Seboettg\Collection\Map\Pair;
16
use Seboettg\Collection\NativePhp\IteratorTrait;
17
use function Seboettg\Collection\Assert\assertScalar;
18
use function Seboettg\Collection\Assert\assertStringable;
19
use function Seboettg\Collection\Assert\assertType;
20
use function Seboettg\Collection\Map\emptyMap;
21
use function Seboettg\Collection\Lists\strval;
22
23
/**
24
 * @property array $array Base array of this data structure
25
 */
26
trait ArrayListTrait
27
{
28
    use IteratorTrait;
29
30
    /**
31
     * flush array list
32
     *
33
     * @return ListInterface|ArrayListTrait
34
     */
35 1
    public function clear(): void
36
    {
37 1
        unset($this->array);
38 1
        $this->array = [];
39 1
    }
40
41
    /**
42
     * {@inheritdoc}
43
     */
44 5
    public function get(int $index)
45
    {
46 5
        return $this->array[$index] ?? null;
47
    }
48
49
    /**
50
     * @param $key
51
     * @param $element
52
     * @return void
53
     */
54
    public function set($key, $element): void
55
    {
56
        $this->array[$key] = $element;
57
    }
58
59
    /**
60
     * Adds the specified element to the end of this list.
61
     *
62
     * @param mixed $element
63
     */
64 9
    public function add($element): void
65
    {
66 9
        end($this->array);
67 9
        $this->array[] = $element;
68 9
    }
69
70
    /**
71
     * @inheritDoc
72
     */
73 1
    public function addAll(iterable $elements): void
74
    {
75 1
        foreach ($elements as $element) {
76 1
            $this->add($element);
77
        }
78 1
    }
79
80
    /**
81
     * @param $key
82
     * @return ListInterface|ArrayListTrait
83
     */
84 1
    public function remove($key): ListInterface
85
    {
86 1
        unset($this->array[$key]);
87 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...
88
    }
89
90
    /**
91
     * {@inheritdoc}
92
     */
93 2
    public function contains($value): bool
94
    {
95 2
        $result = in_array($value, $this->array, true);
96 2
        return ($result !== false);
97
    }
98
99
    /**
100
     * Returns the first element
101
     * @return mixed
102
     */
103 1
    public function first()
104
    {
105 1
        if ($this->isEmpty()) {
106
            return null;
107
        }
108 1
        reset($this->array);
109 1
        return $this->array[key($this->array)];
110
    }
111
112
    /**
113
     * Returns the last element
114
     * @return mixed
115
     */
116 1
    public function last()
117
    {
118 1
        $item = end($this->array);
119 1
        reset($this->array);
120 1
        return $item;
121
    }
122
123
    /**
124
     * {@inheritDoc}
125
     */
126 9
    public function toArray(): array
127
    {
128 9
        return $this->array;
129
    }
130
131
    /**
132
     * Shuffles this list (randomizes the order of the elements in). It uses the PHP function shuffle
133
     * @see http://php.net/manual/en/function.shuffle.php
134
     * @return ListInterface|ArrayListTrait
135
     */
136 1
    public function shuffle(): ListInterface
137
    {
138 1
        shuffle($this->array);
139 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...
140
    }
141
142
    /**
143
     * @inheritDoc
144
     * @param ?callable $predicate
145
     * @param bool $preserveKeys
146
     * @return ListInterface|ArrayListTrait
147
     */
148 3
    public function filter(?callable $predicate = null, bool $preserveKeys = false): ListInterface
149
    {
150 3
        $list = emptyList();
151 3
        $filtered = $predicate == null ? array_filter($this->array) : array_filter($this->array, $predicate);
152 3
        $list->setArray(
153 3
            $preserveKeys ? $filtered : array_values($filtered)
154
        );
155 3
        return $list;
156
    }
157
158
    /**
159
     * @param array $array
160
     */
161 17
    public function setArray(array $array): void
162
    {
163 17
        $this->replace($array);
164 17
    }
165
166
    /**
167
     * @param array $data
168
     */
169 19
    public function replace(array $data): void
170
    {
171 19
        $this->array = $data;
172 19
    }
173
174
    /**
175
     * returns a new ArrayList containing all the elements of this ArrayList after applying the callback function to each one.
176
     * @param callable $mapFunction
177
     * @return ListInterface|ArrayListTrait
178
     */
179 7
    public function map(callable $mapFunction): ListInterface
180
    {
181 7
        $newInstance = emptyList();
182 7
        foreach ($this as $value) {
183 7
            $newInstance->add($mapFunction($value));
184
        }
185 6
        return $newInstance;
186
    }
187
188
    /**
189
     * @inheritDoc
190
     * @param callable $mapFunction
191
     * @return ListInterface
192
     */
193 1
    public function mapNotNull(callable $mapFunction): ListInterface
194
    {
195 1
        $newInstance = $this->map($mapFunction);
196 1
        return $newInstance->filter();
197
    }
198
199
    /**
200
     * Returns a new ArrayList containing a one-dimensional array of all elements of this ArrayList. Keys are going lost.
201
     * @return ListInterface
202
     */
203 1
    public function flatten(): ListInterface
204
    {
205 1
        $flattenedArray = [];
206
        array_walk_recursive($this->array, function ($item) use (&$flattenedArray) {
207 1
            $flattenedArray[] = $item;
208 1
        });
209 1
        return listOf(...$flattenedArray);
210
    }
211
212
    /**
213
     * @inheritDoc
214
     * @param callable $collectFunction
215
     * @return mixed
216
     */
217 1
    public function collect(callable $collectFunction)
218
    {
219 1
        return $collectFunction($this->array);
220
    }
221
222
    /**
223
     * @inheritDoc
224
     * @param string $delimiter
225
     * @param string $prefix
226
     * @param string $suffix
227
     * @return string
228
     */
229 4
    public function joinToString(string $delimiter, string $prefix = null, string $suffix = null): string
230
    {
231
        $result = implode($delimiter, $this->map(function ($item) {
232 4
            assertStringable($item, "Elements in list must be convertible to string in order to use joinToString.");
233 3
            return strval($item);
234 4
        })->toArray());
235 3
        if ($prefix !== null) {
236
            $result = $prefix . $result;
237
        }
238 3
        if ($suffix !== null) {
239
            $result = $result . $suffix;
240
        }
241 3
        return $result;
242
    }
243
244
    /**
245
     * @inheritDoc
246
     * @deprecated use joinToString instead
247
     */
248 1
    public function collectToString(string $delimiter): string
249
    {
250 1
        return $this->joinToString($delimiter);
251
    }
252
253
    /**
254
     * @inheritDoc
255
     * @return int
256
     */
257 7
    public function count(): int
258
    {
259 7
        return count($this->array);
260
    }
261
262
    /**
263
     * @inheritDoc
264
     * @param iterable<scalar> $keys
265
     * @param iterable
266
     */
267
    public function minus(iterable $values): ListInterface
268
    {
269
        if (!$values instanceof ListInterface) {
270
            $valuesList = emptyList();
271
            $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

271
            $valuesList->setArray(/** @scrutinizer ignore-type */ is_array($values) ?? $values->toArray());
Loading history...
272
        } else {
273
            $valuesList = $values;
274
        }
275
        $newInstance = emptyList();
276
        foreach ($this->array as $value) {
277
            if (!$valuesList->contains($value)) {
278
                $newInstance->add($value);
279
            }
280
        }
281
        return $newInstance;
282
    }
283
284
    /**
285
     * @inheritDoc
286
     */
287
    public function groupBy(callable $keySelector): MapInterface
288
    {
289
        $map = emptyMap();
290
        foreach ($this->array as $value) {
291
            $key = $keySelector($value);
292
            if (!$map->contains($key) || !$map[$key] instanceof ListInterface) {
293
                $map->put($key, emptyList());
294
            }
295
            $map->get($key)->add($value);
296
        }
297
        return $map;
298
    }
299
300
    /**
301
     * @inheritDoc
302
     */
303
    public function intersect(ListInterface $list): ListInterface
304
    {
305
        $newInstance = emptyList();
306
        $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...
307
        return $newInstance;
308
    }
309
310
    /**
311
     * @inheritDoc
312
     * @param callable $predicate
313
     * @return Tuple<ListInterface, ListInterface>
314
     */
315
    public function partition(callable $predicate): Tuple
316
    {
317
        $tuple = new Tuple(
318
            emptyList(),
319
            emptyList()
320
        );
321
        $tuple->getFirst()->append(array_filter($this->array, $predicate));
322
        $tuple->getSecond()->append($this->minus($tuple->getFirst()));
323
        return $tuple;
324
    }
325
326
327
    public function plus(iterable $other): ListInterface
328
    {
329
        $list = listOf(...$this->array);
330
        $list->addAll($other);
331
        return $list;
332
    }
333
334
    public function union(ListInterface $other): ListInterface
335
    {
336
        return $this->plus($other);
337
    }
338
339
    public function subtract(ListInterface $other): ListInterface
340
    {
341
        $list = emptyList();
342
        foreach ($this->array as $element) {
343
            if (!$other->contains($element)) {
344
                $list->add($element);
345
            }
346
        }
347
        return $list;
348
    }
349
350
    public function any(callable $predicate): bool
351
    {
352
        return $this->filter($predicate)->count() > 1;
353
    }
354
355
    public function all(callable $predicate): bool
356
    {
357
        return $this->count() === $this->filter($predicate)->count();
358
    }
359
360
    /**
361
     * @inheritDoc
362
     */
363
    public function chunk(int $size): ListInterface
364
    {
365
        $listOfChunks = emptyList();
366
        $arrayChunks = array_chunk($this->array, $size);
367
        foreach ($arrayChunks as $arrayChunk) {
368
            $listOfChunks->add(listOf(...$arrayChunk));
369
        }
370
        return $listOfChunks;
371
    }
372
373
    public function distinct(): ListInterface
374
    {
375
        return listOf(...array_unique($this->array));
376
    }
377
378 4
    public function forEach(callable $action): void
379
    {
380 4
        foreach ($this->array as $element) {
381 4
            $action($element);
382
        }
383 4
    }
384
385
    /**
386
     * @inheritDoc
387
     */
388
    public function getOrElse(int $index, callable $defaultValue)
389
    {
390
        if ($this->array[$index] !== null) {
391
            return $this->array[$index];
392
        }
393
        return $defaultValue();
394
    }
395
396
    /**
397
     * @inheritDoc
398
     * @param int $fromIndex
399
     * @param int $toIndex
400
     * @return ListInterface
401
     */
402
    public function subList(int $fromIndex, int $toIndex): ListInterface
403
    {
404
        $list = emptyList();
405
        for ($i = $fromIndex; $i < $toIndex; ++$i) {
406
            if (isset($this->array[$i])) {
407
                $list->add($this->array[$i]);
408
            }
409
        }
410
        return $list;
411
    }
412
413
    /**
414
     * @inheritDoc
415
     * @param callable $transform f(item: mixed) -> Pair<scalar, mixed>
416
     * @return MapInterface
417
     */
418
    public function associate(callable $transform): MapInterface
419
    {
420
        $map = emptyMap();
421
        foreach ($this->array as $item) {
422
            $pair = $transform($item);
423
            assertType($pair, Pair::class, sprintf(
424
                "The return value of the callable must be of type %s",
425
                Pair::class
426
            ));
427
            assertScalar($pair->getKey(), "The key of the returned Pair of the callable must be a scalar.");
428
            $map[$pair->getKey()] = $pair->getValue();
429
        }
430
        return $map;
431
    }
432
433
    /**
434
     * @inheritDoc
435
     * @param callable $keySelector f(value: mixed) -> scalar
436
     * @return MapInterface
437
     */
438 1
    public function associateBy(callable $keySelector): MapInterface
439
    {
440 1
        $map = emptyMap();
441 1
        foreach ($this->array as $item) {
442 1
            $key = $keySelector($item);
443 1
            assertScalar($key, "The return value of the callable must be a scalar.");
444 1
            $map[$key] = $item;
445
        }
446 1
        return $map;
447
    }
448
449
    /**
450
     * @inheritDoc
451
     * @param callable $valueSelector
452
     * @return MapInterface
453
     */
454 1
    public function associateWith(callable $valueSelector): MapInterface
455
    {
456 1
        $map = emptyMap();
457 1
        foreach ($this->array as $item) {
458 1
            assertScalar($item,
459 1
                "All entries of the list must be scalar values in order to use \"associateWith\".");
460 1
            $map[$item] = $valueSelector($item);
461
        }
462 1
        return $map;
463
    }
464
465
    /**
466
     * Return first element of this list that matches the matchingCondition
467
     *
468
     * @param callable $matchingCondition
469
     * @return mixed|null
470
     */
471
    public function searchBy(callable $matchingCondition)
472
    {
473
        $list = listOf(...array_filter($this->array));
474
        return $list->filter($matchingCondition)->first();
475
    }
476
477 1
    public function isEmpty(): bool
478
    {
479 1
        return $this->count() === 0;
480
    }
481
482 1
    public function toMap(): MapInterface
483
    {
484 1
        $result = emptyMap();
485 1
        foreach ($this->array as $pair) {
486 1
            assertType(
487 1
                $pair,
488 1
                Pair::class,
489 1
                sprintf("Each item of this list must be of type %s.", Pair::class)
490
            );
491 1
            $result[$pair->getKey()] = $pair->getValue();
492
        }
493 1
        return $result;
494
    }
495
}
496