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

ArrayListTrait::minus()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5.2

Importance

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