Passed
Push — version-4 ( e5f5fc...110f5e )
by Sebastian
02:18
created

ArrayListTrait::contains()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 10
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 18
ccs 10
cts 10
cp 1
crap 7
rs 8.8333
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
     * @inheritDoc
67
     */
68 1
    public function remove($key): void
69
    {
70 1
        unset($this->array[$key]);
71 1
    }
72
73
    /**
74
     * {@inheritdoc}
75
     */
76 5
    public function contains($value): bool
77
    {
78 5
        if ((isScalarOrStringable($value) && $this->all(fn($item) => isScalarOrStringable($item)))) {
79 3
            return in_array($value, $this->array, true) !== false;
80
        }
81 2
        if (isComparable($value) && $this->all(fn($item) => isComparable($item))) {
82 1
            $items = $this->array;
83
            /** @var Comparable $value */
84
            /** @var Comparable $item */
85 1
            foreach ($items as $item) {
86 1
                if ($item->compareTo($value) === 0) {
87 1
                    return true;
88
                }
89
            }
90
        } else {
91 1
            return in_array(spl_object_hash($value), array_map(fn($item) => spl_object_hash($item), $this->array), true);
92
        }
93 1
        return false;
94
    }
95
96
    /**
97
     * @inheritDoc
98
     * @see http://php.net/manual/en/function.shuffle.php
99
     * @return ListInterface
100
     */
101 1
    public function shuffle(): ListInterface
102
    {
103 1
        shuffle($this->array);
104 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...
105
    }
106
107
    /**
108
     * @inheritDoc
109
     */
110 12
    public function filter(?callable $predicate = null, bool $preserveKeys = false): ListInterface
111
    {
112 12
        $list = emptyList();
113 12
        $filtered = $predicate == null ? array_filter($this->array) : array_filter($this->array, $predicate);
114 12
        $list->setArray(
115 12
            $preserveKeys ? $filtered : array_values($filtered)
116
        );
117 12
        return $list;
118
    }
119
120
    /**
121
     * @param array $array
122
     */
123 37
    public function setArray(array $array): void
124
    {
125 37
        $this->replace($array);
126 37
    }
127
128
    /**
129
     * @param array $data
130
     */
131 37
    public function replace(array $data): void
132
    {
133 37
        $this->array = $data;
134 37
    }
135
136
    /**
137
     * returns a new ArrayList containing all the elements of this ArrayList after applying the callback function to each one.
138
     * @param callable $mapFunction
139
     * @return ListInterface|ArrayListTrait
140
     */
141 7
    public function map(callable $mapFunction): ListInterface
142
    {
143 7
        $list = emptyList();
144 7
        foreach ($this as $value) {
145 7
            $list->add($mapFunction($value));
146
        }
147 6
        return $list;
148
    }
149
150
    /**
151
     * @inheritDoc
152
     * @param callable $mapFunction
153
     * @return ListInterface
154
     */
155 1
    public function mapNotNull(callable $mapFunction): ListInterface
156
    {
157 1
        $list = $this->map($mapFunction);
158 1
        return $list->filter();
159
    }
160
161
    /**
162
     * Returns a new ArrayList containing a one-dimensional array of all elements of this ArrayList. Keys are going lost.
163
     * @return ListInterface
164
     */
165 1
    public function flatten(): ListInterface
166
    {
167 1
        $flattenedArray = [];
168
        array_walk_recursive($this->array, function ($item) use (&$flattenedArray) {
169 1
            $flattenedArray[] = $item;
170 1
        });
171 1
        return listOf(...$flattenedArray);
172
    }
173
174
    /**
175
     * @inheritDoc
176
     * @param callable $collectFunction
177
     * @return mixed
178
     */
179 1
    public function collect(callable $collectFunction)
180
    {
181 1
        return $collectFunction($this->array);
182
    }
183
184
    /**
185
     * @inheritDoc
186
     */
187 4
    public function joinToString(string $delimiter, string $prefix = null, string $suffix = null): string
188
    {
189
        $result = implode($delimiter, $this->map(function ($item) {
190 4
            assertStringable($item, "Elements in list must be convertible to string in order to use joinToString.");
191 3
            return strval($item);
192 4
        })->toArray());
193 3
        if ($prefix !== null) {
194
            $result = $prefix . $result;
195
        }
196 3
        if ($suffix !== null) {
197
            $result = $result . $suffix;
198
        }
199 3
        return $result;
200
    }
201
202
    /**
203
     * @inheritDoc
204
     * @deprecated use joinToString instead
205
     */
206 1
    public function collectToString(string $delimiter): string
207
    {
208 1
        return $this->joinToString($delimiter);
209
    }
210
211
    /**
212
     * @inheritDoc
213
     * @return int
214
     */
215 17
    public function count(): int
216
    {
217 17
        return count($this->array);
218
    }
219
220
    /**
221
     * @inheritDoc
222
     */
223
    public function size(): int
224
    {
225
        return $this->count();
226
    }
227
228
    /**
229
     * @inheritDoc
230
     * @param callable $predicate - f(item: mixed) -> bool
231
     * @return MapInterface<string, ListInterface>
232
     */
233 1
    public function partition(callable $predicate): MapInterface
234
    {
235 1
        $first = listOf(...array_filter($this->array, $predicate));
236 1
        return mapOf(
237 1
            pair("first", $first),
238 1
            pair("second", $this->minus($first))
239
        );
240
    }
241
242
243
    public function plus(iterable $other): ListInterface
244
    {
245
        $list = listOf(...$this->array);
246
        $list->addAll($other);
247
        return $list;
248
    }
249
250
    /**
251
     * @inheritDoc
252
     */
253 2
    public function minus(iterable $values): ListInterface
254
    {
255 2
        if (!$values instanceof ListInterface) {
256
            $valuesList = emptyList();
257
            $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

257
            $valuesList->setArray(/** @scrutinizer ignore-type */ is_array($values) ?? $values->toArray());
Loading history...
258
        } else {
259 2
            $valuesList = $values;
260
        }
261 2
        $newInstance = emptyList();
262 2
        foreach ($this->array as $value) {
263 2
            if (!$valuesList->contains($value)) {
264 2
                $newInstance->add($value);
265
            }
266
        }
267 2
        return $newInstance;
268
    }
269
270
    /**
271
     * @inheritDoc
272
     */
273
    public function intersect(ListInterface $list): ListInterface
274
    {
275
        $newInstance = emptyList();
276
        $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...
277
        return $newInstance;
278
    }
279
280 2
    public function any(callable $predicate): bool
281
    {
282 2
        return $this->filter($predicate)->count() > 0;
283
    }
284
285 6
    public function all(callable $predicate): bool
286
    {
287 6
        return $this->count() === $this->filter($predicate)->count();
288
    }
289
290
    /**
291
     * @inheritDoc
292
     */
293 1
    public function chunk(int $size): ListInterface
294
    {
295 1
        $listOfChunks = emptyList();
296 1
        $arrayChunks = array_chunk($this->array, $size);
297 1
        foreach ($arrayChunks as $arrayChunk) {
298 1
            $listOfChunks->add(listOf(...$arrayChunk));
299
        }
300 1
        return $listOfChunks;
301
    }
302
303 1
    public function distinct(): ListInterface
304
    {
305 1
        $this->forEach(fn($item) => assertComparable($item,
306 1
            sprintf(
307 1
                "Each item must be of type scalar or implement \Stringable or implement %s",
308 1
                Comparable::class
309
            )
310 1
        ));
311 1
        $newList = emptyList();
312 1
        if ($this->all(fn($item): bool => isScalarOrStringable($item))) {
313
            return listFromArray(array_unique($this->toArray()));
314
        } else {
315 1
            if ($this->all(fn($item): bool => isComparable($item))) {
316 1
                $values = $this->array;
317 1
                foreach ($values as $value) {
318 1
                    if (!$newList->contains($value)) {
319 1
                        $newList->add($value);
320
                    }
321
                }
322 1
                return $newList;
323
            }
324
        }
325
        return listFromArray($this->array);
326
    }
327
328
    /**
329
     * @inheritDoc
330
     */
331 6
    public function forEach(callable $action): void
332
    {
333 6
        foreach ($this->array as $element) {
334 6
            $action($element);
335
        }
336 6
    }
337
338
    /**
339
     * @inheritDoc
340
     */
341
    public function getOrElse(int $index, callable $defaultValue)
342
    {
343
        if ($this->array[$index] !== null) {
344
            return $this->array[$index];
345
        }
346
        return $defaultValue();
347
    }
348
349
    /**
350
     * @inheritDoc
351
     * @param int $fromIndex
352
     * @param int $toIndex
353
     * @return ListInterface
354
     */
355
    public function subList(int $fromIndex, int $toIndex): ListInterface
356
    {
357
        $list = emptyList();
358
        for ($i = $fromIndex; $i < $toIndex; ++$i) {
359
            if (isset($this->array[$i])) {
360
                $list->add($this->array[$i]);
361
            }
362
        }
363
        return $list;
364
    }
365
366
    /**
367
     * Return first element of this list that matches the matchingCondition
368
     *
369
     * @param callable $matchingCondition
370
     * @return mixed|null
371
     */
372
    public function searchBy(callable $matchingCondition)
373
    {
374
        $list = listOf(...array_filter($this->array));
375
        return $list->filter($matchingCondition)->first();
376
    }
377
378
    public function isEmpty(): bool
379
    {
380
        return $this->count() === 0;
381
    }
382
383
    /**
384
     * {@inheritDoc}
385
     */
386 9
    public function toArray(): array
387
    {
388 9
        return $this->array;
389
    }
390
}
391