Passed
Branch master (e93341)
by Maxim
02:17
created

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