Passed
Push — version-4 ( d2a5d9...7cacf2 )
by Sebastian
07:43
created

ArrayListTrait::contains()   B

Complexity

Conditions 9
Paths 6

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 9.0468

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 9
eloc 13
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 22
ccs 11
cts 12
cp 0.9167
crap 9.0468
rs 8.0555
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
use function Seboettg\Collection\Lists\in_array;
24
25
/**
26
 * @property array $array Base array of this data structure
27
 */
28
trait ArrayListTrait
29
{
30
    use ListAccessTrait;
31
    use IteratorTrait;
32
    use MapFeaturesTrait;
33
34
    /**
35
     * flush array list
36
     *
37
     * @return ListInterface|ArrayListTrait
38
     */
39 1
    public function clear(): void
40
    {
41 1
        unset($this->array);
42 1
        $this->array = [];
43 1
    }
44
45
    /**
46
     * Adds the specified element to the end of this list.
47
     *
48
     * @param mixed $element
49
     */
50 18
    public function add($element): void
51
    {
52 18
        end($this->array);
53 18
        $this->array[] = $element;
54 18
    }
55
56
    /**
57
     * @inheritDoc
58
     */
59 1
    public function addAll(iterable $elements): void
60
    {
61 1
        foreach ($elements as $element) {
62 1
            $this->add($element);
63
        }
64 1
    }
65
66
    /**
67
     * @inheritDoc
68
     */
69 1
    public function remove($key): void
70
    {
71 1
        unset($this->array[$key]);
72 1
    }
73
74
    /**
75
     * {@inheritdoc}
76
     */
77 7
    public function contains($value): bool
78
    {
79 7
        if ((isScalarOrStringable($value) && $this->all(fn($item) => isScalarOrStringable($item)))) {
80 5
            return in_array($value, $this->array) !== false;
81
        }
82 2
        if (isComparable($value) && $this->all(fn($item) => isComparable($item))) {
83 1
            $items = $this->array;
84
            /** @var Comparable $value */
85
            /** @var Comparable $item */
86 1
            foreach ($items as $item) {
87 1
                if ($item->compareTo($value) === 0) {
88 1
                    return true;
89
                }
90
            }
91
        } else {
92 1
            if ($value instanceof ListInterface && $this->all(fn($item) => $item instanceof ListInterface)) {
93 1
                return in_array(print_r($value->toArray(), true), array_map(fn ($item) => print_r($item->toArray(), true), $this->array)) !== false;
94
            } else {
95
                return in_array(spl_object_hash($value), array_map(fn($item) => spl_object_hash($item), $this->array));
96
            }
97
        }
98 1
        return false;
99
    }
100
101
    /**
102
     * @inheritDoc
103
     */
104 1
    public function shuffle(): ListInterface
105
    {
106 1
        $array = $this->array;
107 1
        shuffle($array);
108 1
        return listFromArray($array);
109
    }
110
111
    /**
112
     * @inheritDoc
113
     */
114 15
    public function filter(?callable $predicate = null, bool $preserveKeys = false): ListInterface
115
    {
116 15
        $list = emptyList();
117 15
        $filtered = $predicate == null ? array_filter($this->array) : array_filter($this->array, $predicate);
118 15
        $list->setArray(
119 15
            $preserveKeys ? $filtered : array_values($filtered)
120
        );
121 15
        return $list;
122
    }
123
124
    /**
125
     * @param array $array
126
     */
127 39
    public function setArray(array $array): void
128
    {
129 39
        $this->replace($array);
130 39
    }
131
132
    /**
133
     * @param array $data
134
     */
135 39
    public function replace(array $data): void
136
    {
137 39
        $this->array = $data;
138 39
    }
139
140
    /**
141
     * returns a new ArrayList containing all the elements of this ArrayList after applying the callback function to each one.
142
     * @param callable $mapFunction
143
     * @return ListInterface|ArrayListTrait
144
     */
145 7
    public function map(callable $mapFunction): ListInterface
146
    {
147 7
        $list = emptyList();
148 7
        foreach ($this as $value) {
149 7
            $list->add($mapFunction($value));
150
        }
151 6
        return $list;
152
    }
153
154
    /**
155
     * @inheritDoc
156
     * @param callable $mapFunction
157
     * @return ListInterface
158
     */
159 1
    public function mapNotNull(callable $mapFunction): ListInterface
160
    {
161 1
        $list = $this->map($mapFunction);
162 1
        return $list->filter();
163
    }
164
165
    /**
166
     * Returns a new ArrayList containing a one-dimensional array of all elements of this ArrayList. Keys are going lost.
167
     * @return ListInterface
168
     */
169 1
    public function flatten(): ListInterface
170
    {
171 1
        $flattenedArray = [];
172
        array_walk_recursive($this->array, function ($item) use (&$flattenedArray) {
173 1
            $flattenedArray[] = $item;
174 1
        });
175 1
        return listOf(...$flattenedArray);
176
    }
177
178
    /**
179
     * @inheritDoc
180
     * @param callable $collectFunction
181
     * @return mixed
182
     */
183 1
    public function collect(callable $collectFunction)
184
    {
185 1
        return $collectFunction($this->array);
186
    }
187
188
    /**
189
     * @inheritDoc
190
     */
191 4
    public function joinToString(string $delimiter, string $prefix = null, string $suffix = null): string
192
    {
193
        $result = implode($delimiter, $this->map(function ($item) {
194 4
            assertStringable($item, "Elements in list must be convertible to string in order to use joinToString.");
195 3
            return strval($item);
196 4
        })->toArray());
197 3
        if ($prefix !== null) {
198
            $result = $prefix . $result;
199
        }
200 3
        if ($suffix !== null) {
201
            $result = $result . $suffix;
202
        }
203 3
        return $result;
204
    }
205
206
    /**
207
     * @inheritDoc
208
     * @deprecated use joinToString instead
209
     */
210 1
    public function collectToString(string $delimiter): string
211
    {
212 1
        return $this->joinToString($delimiter);
213
    }
214
215
    /**
216
     * @inheritDoc
217
     * @return int
218
     */
219 19
    public function count(): int
220
    {
221 19
        return count($this->array);
222
    }
223
224
    /**
225
     * @inheritDoc
226
     */
227
    public function size(): int
228
    {
229
        return $this->count();
230
    }
231
232
    /**
233
     * @inheritDoc
234
     * @param callable $predicate - f(item: mixed) -> bool
235
     * @return MapInterface<string, ListInterface>
236
     */
237 1
    public function partition(callable $predicate): MapInterface
238
    {
239 1
        $first = listOf(...array_filter($this->array, $predicate));
240 1
        return mapOf(
241 1
            pair("first", $first),
242 1
            pair("second", $this->minus($first))
243
        );
244
    }
245
246
247
    public function plus(iterable $other): ListInterface
248
    {
249
        $list = listOf(...$this->array);
250
        $list->addAll($other);
251
        return $list;
252
    }
253
254
    /**
255
     * @inheritDoc
256
     */
257 2
    public function minus(iterable $values): ListInterface
258
    {
259 2
        $valuesList = emptyList();
260 2
        if (!$values instanceof ListInterface && is_array($values)) {
261
            $valuesList->setArray($values);
262
        } else {
263 2
            $valuesList = $values;
264
        }
265 2
        $newInstance = emptyList();
266 2
        foreach ($this->array as $value) {
267 2
            if (!$valuesList->contains($value)) {
268 2
                $newInstance->add($value);
269
            }
270
        }
271 2
        return $newInstance;
272
    }
273
274
    /**
275
     * @inheritDoc
276
     */
277 2
    public function intersect(ListInterface $list): ListInterface
278
    {
279 2
        $result = emptyList();
280 2
        foreach ($list as $item) {
281 2
            if ($this->contains($item)) {
282 2
                $result->add($item);
283
            }
284
        }
285 2
        return $result;
286
    }
287
288 2
    public function any(callable $predicate): bool
289
    {
290 2
        return $this->filter($predicate)->count() > 0;
291
    }
292
293 9
    public function all(callable $predicate): bool
294
    {
295 9
        return $this->count() === $this->filter($predicate)->count();
296
    }
297
298
    /**
299
     * @inheritDoc
300
     */
301 1
    public function chunk(int $size): ListInterface
302
    {
303 1
        $listOfChunks = emptyList();
304 1
        $arrayChunks = array_chunk($this->array, $size);
305 1
        foreach ($arrayChunks as $arrayChunk) {
306 1
            $listOfChunks->add(listOf(...$arrayChunk));
307
        }
308 1
        return $listOfChunks;
309
    }
310
311 1
    public function distinct(): ListInterface
312
    {
313 1
        $this->forEach(fn($item) => assertComparable($item,
314 1
            sprintf(
315 1
                "Each item must be of type scalar or implement \Stringable or implement %s",
316 1
                Comparable::class
317
            )
318 1
        ));
319 1
        $newList = emptyList();
320 1
        if ($this->all(fn($item): bool => isScalarOrStringable($item))) {
321
            return listFromArray(array_unique($this->toArray()));
322
        } else {
323 1
            if ($this->all(fn($item): bool => isComparable($item))) {
324 1
                $values = $this->array;
325 1
                foreach ($values as $value) {
326 1
                    if (!$newList->contains($value)) {
327 1
                        $newList->add($value);
328
                    }
329
                }
330 1
                return $newList;
331
            }
332
        }
333
        return listFromArray($this->array);
334
    }
335
336
    /**
337
     * @inheritDoc
338
     */
339 6
    public function forEach(callable $action): void
340
    {
341 6
        foreach ($this->array as $element) {
342 6
            $action($element);
343
        }
344 6
    }
345
346
    /**
347
     * @inheritDoc
348
     */
349
    public function getOrElse(int $index, callable $defaultValue)
350
    {
351
        if ($this->array[$index] !== null) {
352
            return $this->array[$index];
353
        }
354
        return $defaultValue();
355
    }
356
357
    /**
358
     * @inheritDoc
359
     * @param int $fromIndex
360
     * @param int $toIndex
361
     * @return ListInterface
362
     */
363
    public function subList(int $fromIndex, int $toIndex): ListInterface
364
    {
365
        $list = emptyList();
366
        for ($i = $fromIndex; $i < $toIndex; ++$i) {
367
            if (isset($this->array[$i])) {
368
                $list->add($this->array[$i]);
369
            }
370
        }
371
        return $list;
372
    }
373
374
    /**
375
     * Return first element of this list that matches the matchingCondition
376
     *
377
     * @param callable $matchingCondition
378
     * @return mixed|null
379
     */
380
    public function searchBy(callable $matchingCondition)
381
    {
382
        $list = listOf(...array_filter($this->array));
383
        return $list->filter($matchingCondition)->first();
384
    }
385
386
    public function isEmpty(): bool
387
    {
388
        return $this->count() === 0;
389
    }
390
391
    /**
392
     * {@inheritDoc}
393
     */
394 10
    public function toArray(): array
395
    {
396 10
        return $this->array;
397
    }
398
}
399