SerialStream::reorganize()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 10
c 1
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
/**
3
 * @author Maxim Sokolovsky
4
 */
5
6
namespace WS\Utils\Collections;
7
8
use RuntimeException;
9
10
class SerialStream implements Stream
11
{
12
    /**
13
     * @var ListSequence
14
     */
15
    private $list;
16
17 162
    public function __construct(Collection $collection)
18
    {
19 162
        if ($collection instanceof ListSequence) {
20 159
            $this->list = $collection->copy();
21
        } else {
22 3
            $this->list = $this->emptyList();
23 3
            $this->list->addAll($collection->toArray());
24
        }
25 162
    }
26
27
    /**
28
     * @inheritDoc
29
     */
30 22
    public function each(callable $consumer): Stream
31
    {
32 22
        $i = 0;
33 22
        foreach ($this->list as $item) {
34 21
            $consumer($item, $i++);
35
        }
36 21
        return $this;
37
    }
38
39
    /**
40
     * @inheritDoc
41
     */
42 29
    public function filter(callable $predicate): Stream
43
    {
44 29
        $collection = $this->list;
45 29
        $this->list = $this->emptyList();
46
47 29
        foreach ($collection as $item) {
48 28
            if ($predicate($item)) {
49 28
                $this->list->add($item);
50
            }
51
        }
52
53 29
        return $this;
54
    }
55
56 14
    public function reorganize(callable $reorganizer): Stream
57
    {
58 14
        $reorganizedCollection = $reorganizer($this->list->copy());
59 14
        if (! $reorganizedCollection instanceof Collection) {
60 1
            throw new RuntimeException('Result set of reorganizer call must be instance of Collection interface');
61
        }
62 13
        $this->list = $reorganizedCollection;
63
64 13
        return $this;
65
    }
66
67
    /**
68
     * @inheritDoc
69
     */
70 3
    public function allMatch(callable $predicate): bool
71
    {
72 3
        foreach ($this->list as $item) {
73 2
            if (!$predicate($item)) {
74 2
                return false;
75
            }
76
        }
77 2
        return true;
78
    }
79
80
    /**
81
     * @inheritDoc
82
     */
83 5
    public function anyMatch(callable $predicate): bool
84
    {
85 5
        foreach ($this->list as $item) {
86 4
            if ($predicate($item)) {
87 4
                return true;
88
            }
89
        }
90
91 3
        return false;
92
    }
93
94
    /**
95
     * @inheritDoc
96
     */
97 13
    public function map(callable $converter): Stream
98
    {
99 13
        $collection = $this->list;
100 13
        $this->list = $this->emptyList();
101
102 13
        foreach ($collection as $item) {
103 12
            $this->list->add($converter($item));
104
        }
105 13
        return $this;
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111 15
    public function sort(callable $comparator): Stream
112
    {
113 15
        $collection = $this->getCollection();
114 15
        $this->list = $this->emptyList();
115
116 15
        $array = $collection->toArray();
117 15
        usort($array, $comparator);
118 15
        foreach ($array as $item) {
119 13
            $this->list->add($item);
120
        }
121
122 15
        return $this;
123
    }
124
125 10
    public function sortBy(callable $extractor): Stream
126
    {
127 10
        $values = [];
128 10
        $map = [];
129
        $this->each(static function ($el) use ($extractor, & $map, & $values) {
130 10
            $value = $extractor($el);
131 10
            if (!is_scalar($value)) {
132 1
                throw new RuntimeException('Only scalar value can be as result of sort extractor');
133
            }
134 9
            $values[] = $value;
135 9
            $map[$value.''][] = $el;
136 10
        });
137 9
        sort($values);
138 9
        $newList = $this->emptyList();
139 9
        foreach ($values as $value) {
140 9
            $key = $value.'';
141 9
            $els = $map[$key] ?? [];
142 9
            $newList->addAll($els);
143 9
            unset($map[$key]);
144
        }
145 9
        $this->list = $newList;
146
147 9
        return $this;
148
    }
149
150 4
    public function sortByDesc(callable $extractor): Stream
151
    {
152 4
        $this->sortBy($extractor)
153 4
            ->reverse();
154
155 4
        return $this;
156
    }
157
158
    /**
159
     * @inheritDoc
160
     */
161 4
    public function sortDesc(callable $comparator): Stream
162
    {
163 4
        $this->sort($comparator)
164 4
            ->reverse();
165
166 4
        return $this;
167
    }
168
169 12
    public function reverse(): Stream
170
    {
171 12
        $array = $this->list->toArray();
172 12
        $reversedArray = array_reverse($array);
173 12
        $this->list = $this->emptyList();
174 12
        $this->list->addAll($reversedArray);
175 12
        return $this;
176
    }
177
178
    /**
179
     * @inheritDoc
180
     */
181 18
    public function collect(callable $collector)
182
    {
183 18
        return $collector($this->getCollection()->copy());
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189 4
    public function findAny()
190
    {
191 4
        $size =  $this->list->size();
192 4
        if ($size === 0) {
193 1
            return null;
194
        }
195
        /** @noinspection PhpUnhandledExceptionInspection */
196 3
        $rIndex = random_int(0, $size - 1);
197 3
        $pointer = 0;
198 3
        $item = null;
199 3
        foreach ($this->list as $item) {
200 3
            if ($rIndex === $pointer++) {
201 3
                break;
202
            }
203
        }
204 3
        return $item;
205
    }
206
207
    /**
208
     * @inheritDoc
209
     */
210 23
    public function findFirst(callable $filter = null)
211
    {
212 23
        if (!$filter) {
213
            /** @noinspection LoopWhichDoesNotLoopInspection */
214 20
            foreach ($this->list as $item) {
215 19
                return $item;
216
            }
217 1
            return null;
218
        }
219
        /** @noinspection LoopWhichDoesNotLoopInspection */
220 3
        foreach ($this->list as $item) {
221 2
            if ($filter($item)) {
222 2
                return $item;
223
            }
224
        }
225 2
        return null;
226
    }
227
228
    /**
229
     * @inheritDoc
230
     */
231 4
    public function min(callable $comparator)
232
    {
233 4
        $collection = $this->getCollection();
234 4
        if ($collection->size() === 0) {
235 1
            return null;
236
        }
237
238 3
        $array = $collection->toArray();
239
240 3
        $el = array_shift($array);
241
242 3
        foreach ($array as $item) {
243 2
            if ($comparator($item, $el) < 0) {
244 2
                $el = $item;
245
            }
246
        }
247
248 3
        return $el;
249
    }
250
251
    /**
252
     * @inheritDoc
253
     */
254 4
    public function max(callable $comparator)
255
    {
256 4
        $collection = $this->getCollection();
257 4
        if ($collection->size() === 0) {
258 1
            return null;
259
        }
260
261 3
        $array = $collection->toArray();
262 3
        $el = null;
263
264 3
        foreach ($array as $item) {
265 3
            if ($comparator($item, $el) > 0) {
266 3
                $el = $item;
267
            }
268
        }
269
270 3
        return $el;
271
    }
272
273
    /**
274
     * @inheritDoc
275
     */
276 4
    public function reduce(callable $accumulator, $initialValue = null)
277
    {
278 4
        $accumulate = $initialValue;
279 4
        foreach ($this->list as $item) {
280 2
            $accumulate = $accumulator($item, $accumulate);
281
        }
282 4
        return $accumulate;
283
    }
284
285 112
    public function getCollection(): Collection
286
    {
287 112
        return $this->list->copy();
288
    }
289
290 66
    private function emptyList(): Collection
291
    {
292 66
        return ArrayList::of();
293
    }
294
295 19
    public function findLast()
296
    {
297 19
        $array = $this->list->toArray();
298 19
        return array_pop($array);
299
    }
300
301 3
    public function walk(callable $consumer, ?int $limit = null): Stream
302
    {
303 3
        $iterationsCount = $limit ?? $this->list->size();
304 3
        foreach ($this->list as $i => $item) {
305 3
            $consumerRes = $consumer($item, $i);
306 3
            if ($consumerRes === false) {
307 1
                break;
308
            }
309 3
            if ($i + 1 >= $iterationsCount) {
310 3
                break;
311
            }
312
        }
313
314 3
        return $this;
315
    }
316
317 1
    public function limit(int $size): Stream
318
    {
319 1
        $newCollection = $this->emptyList();
320
        $this->walk(static function ($el) use ($newCollection) {
321 1
            $newCollection->add($el);
322 1
        }, $size);
323
324 1
        $this->list = $newCollection;
325 1
        return $this;
326
    }
327
328 16
    public function when(bool $condition): Stream
329
    {
330 16
        if (!$condition) {
331 15
            return new DummyStreamDecorator($this);
332
        }
333
334 1
        return $this;
335
    }
336
337 1
    public function always(): Stream
338
    {
339 1
        return $this;
340
    }
341
342
    /**
343
     * @inheritDoc
344
     */
345 2
    public function toArray(): array
346
    {
347
        return $this
348 2
            ->getCollection()
349 2
            ->toArray()
350
        ;
351
    }
352
353
    /**
354
     * @inheritDoc
355
     */
356 1
    public function getSet(): Set
357
    {
358 1
        return new HashSet($this->toArray());
359
    }
360
}
361