Passed
Push — master ( 94a554...9cd63a )
by Maxim
04:24 queued 02:10
created

SerialStream::reduce()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

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