Passed
Push — version-4 ( 7cacf2...844ef0 )
by Sebastian
02:23
created

ArrayListTrait::collect()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

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 2
cts 2
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
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 21
    public function add($element): void
51
    {
52 21
        end($this->array);
53 21
        $this->array[] = $element;
54 21
    }
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 8
    public function contains($value): bool
78
    {
79 8
        if ((isScalarOrStringable($value) && $this->all(fn($item) => isScalarOrStringable($item)))) {
80 5
            return in_array($value, $this->array) !== false;
81
        }
82 3
        if (isComparable($value) && $this->all(fn($item) => isComparable($item))) {
83 2
            $items = $this->array;
84
            /** @var Comparable $value */
85
            /** @var Comparable $item */
86 2
            foreach ($items as $item) {
87 2
                if ($item->compareTo($value) === 0) {
88 2
                    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 2
        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 16
    public function filter(?callable $predicate = null, bool $preserveKeys = false): ListInterface
115
    {
116 16
        $list = emptyList();
117 16
        $filtered = $predicate == null ? array_filter($this->array) : array_filter($this->array, $predicate);
118 16
        $list->setArray(
119 16
            $preserveKeys ? $filtered : array_values($filtered)
120
        );
121 16
        return $list;
122
    }
123
124
    /**
125
     * @param array $array
126
     */
127 45
    public function setArray(array $array): void
128
    {
129 45
        $this->replace($array);
130 45
    }
131
132
    /**
133
     * @param array $data
134
     */
135 45
    public function replace(array $data): void
136
    {
137 45
        $this->array = $data;
138 45
    }
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(
195 4
                $item,
196 4
                "All elements in the list must be convertible to string in order to use joinToString."
197
            );
198 3
            return strval($item);
199 4
        })->toArray());
200 3
        if ($prefix !== null) {
201
            $result = $prefix . $result;
202
        }
203 3
        if ($suffix !== null) {
204
            $result = $result . $suffix;
205
        }
206 3
        return $result;
207
    }
208
209
    /**
210
     * @inheritDoc
211
     * @deprecated use joinToString instead
212
     */
213 1
    public function collectToString(string $delimiter): string
214
    {
215 1
        return $this->joinToString($delimiter);
216
    }
217
218
    /**
219
     * @inheritDoc
220
     * @return int
221
     */
222 21
    public function count(): int
223
    {
224 21
        return count($this->array);
225
    }
226
227
    /**
228
     * @inheritDoc
229
     */
230
    public function size(): int
231
    {
232
        return $this->count();
233
    }
234
235
    /**
236
     * @inheritDoc
237
     * @param callable $predicate - f(item: mixed) -> bool
238
     * @return MapInterface<string, ListInterface>
239
     */
240 1
    public function partition(callable $predicate): MapInterface
241
    {
242 1
        $first = listOf(...array_filter($this->array, $predicate));
243 1
        return mapOf(
244 1
            pair("first", $first),
245 1
            pair("second", $this->minus($first))
246
        );
247
    }
248
249
250
    public function plus(iterable $other): ListInterface
251
    {
252
        $list = listOf(...$this->array);
253
        $list->addAll($other);
254
        return $list;
255
    }
256
257
    /**
258
     * @inheritDoc
259
     */
260 3
    public function minus(iterable $values): ListInterface
261
    {
262 3
        $valuesList = emptyList();
263 3
        if (!$values instanceof ListInterface && is_array($values)) {
264
            $valuesList->setArray($values);
265
        } else {
266 3
            $valuesList = $values;
267
        }
268 3
        $newInstance = emptyList();
269 3
        foreach ($this->array as $value) {
270 3
            if (!$valuesList->contains($value)) {
271 3
                $newInstance->add($value);
272
            }
273
        }
274 3
        return $newInstance;
275
    }
276
277
    /**
278
     * @inheritDoc
279
     */
280 2
    public function intersect(ListInterface $list): ListInterface
281
    {
282 2
        $result = emptyList();
283 2
        foreach ($list as $item) {
284 2
            if ($this->contains($item)) {
285 2
                $result->add($item);
286
            }
287
        }
288 2
        return $result;
289
    }
290
291 2
    public function any(callable $predicate): bool
292
    {
293 2
        return $this->filter($predicate)->count() > 0;
294
    }
295
296 10
    public function all(callable $predicate): bool
297
    {
298 10
        return $this->count() === $this->filter($predicate)->count();
299
    }
300
301
    /**
302
     * @inheritDoc
303
     */
304 2
    public function chunk(int $size): ListInterface
305
    {
306 2
        $listOfChunks = emptyList();
307 2
        $arrayChunks = array_chunk($this->array, $size);
308 2
        foreach ($arrayChunks as $arrayChunk) {
309 2
            $listOfChunks->add(listOf(...$arrayChunk));
310
        }
311 2
        return $listOfChunks;
312
    }
313
314 1
    public function distinct(): ListInterface
315
    {
316 1
        $this->forEach(fn($item) => assertComparable($item,
317 1
            sprintf(
318 1
                "Each item must be of type scalar or implement \Stringable or implement %s",
319 1
                Comparable::class
320
            )
321 1
        ));
322 1
        $newList = emptyList();
323 1
        if ($this->all(fn($item): bool => isScalarOrStringable($item))) {
324
            return listFromArray(array_unique($this->toArray()));
325
        } else {
326 1
            if ($this->all(fn($item): bool => isComparable($item))) {
327 1
                $values = $this->array;
328 1
                foreach ($values as $value) {
329 1
                    if (!$newList->contains($value)) {
330 1
                        $newList->add($value);
331
                    }
332
                }
333 1
                return $newList;
334
            }
335
        }
336
        return listFromArray($this->array);
337
    }
338
339
    /**
340
     * @inheritDoc
341
     */
342 7
    public function forEach(callable $action): void
343
    {
344 7
        foreach ($this->array as $element) {
345 7
            $action($element);
346
        }
347 7
    }
348
349
    /**
350
     * @inheritDoc
351
     */
352
    public function getOrElse(int $index, callable $defaultValue)
353
    {
354
        if ($this->array[$index] !== null) {
355
            return $this->array[$index];
356
        }
357
        return $defaultValue();
358
    }
359
360
    /**
361
     * @inheritDoc
362
     * @param int $fromIndex
363
     * @param int $toIndex
364
     * @return ListInterface
365
     */
366
    public function subList(int $fromIndex, int $toIndex): ListInterface
367
    {
368
        $list = emptyList();
369
        for ($i = $fromIndex; $i < $toIndex; ++$i) {
370
            if (isset($this->array[$i])) {
371
                $list->add($this->array[$i]);
372
            }
373
        }
374
        return $list;
375
    }
376
377
    /**
378
     * Return first element of this list that matches the matchingCondition
379
     *
380
     * @param callable $matchingCondition
381
     * @return mixed|null
382
     */
383
    public function searchBy(callable $matchingCondition)
384
    {
385
        $list = listOf(...array_filter($this->array));
386
        return $list->filter($matchingCondition)->first();
387
    }
388
389
    public function isEmpty(): bool
390
    {
391
        return $this->count() === 0;
392
    }
393
394
    /**
395
     * {@inheritDoc}
396
     */
397 10
    public function toArray(): array
398
    {
399 10
        return $this->array;
400
    }
401
}
402