Skip to content

Commit 7b98c7e

Browse files
committed
feat: add underscore collectionn class
1 parent dc54d1f commit 7b98c7e

File tree

1 file changed

+287
-0
lines changed

1 file changed

+287
-0
lines changed

src/UnderscoreCollection.php

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
<?php
2+
3+
namespace Ahc\Underscore;
4+
5+
class UnderscoreCollection extends UnderscoreArray
6+
{
7+
public function each(callable $fn)
8+
{
9+
foreach ($this->data as $index => $value) {
10+
$fn($value, $index);
11+
}
12+
13+
return $this;
14+
}
15+
16+
public function map(callable $fn)
17+
{
18+
$data = [];
19+
20+
foreach ($this->data as $index => $value) {
21+
$data[$index] = $fn($value, $index);
22+
}
23+
24+
return new static($data);
25+
}
26+
27+
public function collect(callable $fn)
28+
{
29+
return $this->map($fn);
30+
}
31+
32+
public function reduce(callable $fn, $memo)
33+
{
34+
return \array_reduce($this->data, $fn, $memo);
35+
}
36+
37+
public function foldl(callable $fn, $memo)
38+
{
39+
return $this->reduce($fn, $memo);
40+
}
41+
42+
public function inject(callable $fn, $memo)
43+
{
44+
return $this->reduce($fn, $memo);
45+
}
46+
47+
public function reduceRight(callable $fn, $memo)
48+
{
49+
return \array_reduce(\array_reverse($this->data), $fn, $memo);
50+
}
51+
52+
public function foldr(callable $fn, $memo)
53+
{
54+
return $this->reduceRight($fn, $memo);
55+
}
56+
57+
public function find(callable $fn)
58+
{
59+
foreach ($this->data as $index => $value) {
60+
if ($fn($value, $index)) {
61+
return $value;
62+
}
63+
}
64+
}
65+
66+
public function detect(callable $fn)
67+
{
68+
return $this->find($fn);
69+
}
70+
71+
public function filter(callable $fn)
72+
{
73+
$data = \array_filter($this->data, $fn, \ARRAY_FILTER_USE_BOTH);
74+
75+
return new static($data);
76+
}
77+
78+
public function select(callable $fn)
79+
{
80+
return $this->filter($fn);
81+
}
82+
83+
public function reject(callable $fn)
84+
{
85+
$data = \array_filter($this->data, $this->negate($fn), \ARRAY_FILTER_USE_BOTH);
86+
87+
return new static($data);
88+
}
89+
90+
public function every(callable $fn)
91+
{
92+
return $this->match($fn, true);
93+
}
94+
95+
public function all(callable $fn)
96+
{
97+
return $this->every($fn);
98+
}
99+
100+
public function some(callable $fn)
101+
{
102+
return $this->match($fn, false);
103+
}
104+
105+
public function any(callable $fn)
106+
{
107+
return $this->some($fn);
108+
}
109+
110+
protected function match(callable $fn, $all = true)
111+
{
112+
foreach ($this->data as $index => $value) {
113+
if ($all ^ $fn($value, $index)) {
114+
return !$all;
115+
}
116+
}
117+
118+
return $all;
119+
}
120+
121+
public function contains($item)
122+
{
123+
return \in_array($item, $this->data);
124+
}
125+
126+
public function includes($item)
127+
{
128+
return $this->contains($item);
129+
}
130+
131+
public function invoke(callable $fn)
132+
{
133+
return \call_user_func_array($fn, $this->data);
134+
}
135+
136+
public function pluck($columnKey, $indexKey = null)
137+
{
138+
$data = \array_column($this->data, $columnKey, $indexKey);
139+
140+
return new static($data);
141+
}
142+
143+
public function where(array $props)
144+
{
145+
return $this->filter($this->matcher($props));
146+
}
147+
148+
public function findWhere(array $props)
149+
{
150+
return $this->find($this->matcher($props));
151+
}
152+
153+
protected function matcher(array $props)
154+
{
155+
return function ($value, $index) use ($props) {
156+
foreach ($props as $prop => $criteria) {
157+
if (\array_column([$value], $prop) != [$criteria]) {
158+
return false;
159+
}
160+
}
161+
162+
return true;
163+
};
164+
}
165+
166+
public function max($fn = null)
167+
{
168+
return $this->maxMin($fn, true);
169+
}
170+
171+
public function min($fn = null)
172+
{
173+
return $this->maxMin($fn, false);
174+
}
175+
176+
protected function maxMin($fn = null, $isMax = true)
177+
{
178+
$fn = $this->valueFn($fn);
179+
180+
return $this->reduce(function ($carry, $value) use ($fn, $isMax) {
181+
$value = $fn($value);
182+
183+
if (!\is_numeric($value)) {
184+
return $carry;
185+
}
186+
187+
return null === $carry
188+
? $value
189+
: ($isMax ? \max($carry, $value) : \min($carry, $value));
190+
}, null);
191+
}
192+
193+
public function shuffle()
194+
{
195+
$data = [];
196+
$keys = \array_keys($this->data);
197+
198+
shuffle($keys);
199+
200+
foreach ($keys as $index) {
201+
$data[$index] = $this->data[$index];
202+
}
203+
204+
return new static($data);
205+
}
206+
207+
public function sample($n = 1)
208+
{
209+
$shuffled = $this->shuffle()->get();
210+
211+
return new static(\array_slice($shuffled, 0, $n, true));
212+
}
213+
214+
public function sortBy($fn)
215+
{
216+
$data = $this->map($this->valueFn($fn))->get();
217+
218+
\asort($data); // Keep keys.
219+
220+
foreach ($data as $index => $value) {
221+
$data[$index] = $this->data[$index];
222+
}
223+
224+
return new static($data);
225+
}
226+
227+
public function groupBy($fn)
228+
{
229+
return $this->group($fn, true);
230+
}
231+
232+
public function indexBy($fn)
233+
{
234+
return $this->group($fn, false);
235+
}
236+
237+
public function countBy($fn)
238+
{
239+
$data = [];
240+
241+
foreach ($this->group($fn, true) as $index => $value) {
242+
$data[$index] = \count($value);
243+
}
244+
245+
return new static($data);
246+
}
247+
248+
protected function group($fn, $isGroup = true)
249+
{
250+
$data = [];
251+
$fn = $this->valueFn($fn);
252+
253+
foreach ($this->data as $index => $value) {
254+
$isGroup ? $data[$fn($value)][$index] = $value : $data[$fn($value)] = $value;
255+
}
256+
257+
return new static($data);
258+
}
259+
260+
public function toArray()
261+
{
262+
return $this->map(function ($value) {
263+
if (\is_scalar($value)) {
264+
return $value;
265+
}
266+
267+
return $this->asArray($value);
268+
})->get();
269+
}
270+
271+
public function size()
272+
{
273+
return $this->count();
274+
}
275+
276+
public function partition($fn)
277+
{
278+
$data = [[/* pass */], [/* fail */]];
279+
$fn = $this->valueFn($fn);
280+
281+
$this->each(function ($value, $key) use ($fn, &$data) {
282+
$data[$fn($value, $key) ? 0 : 1][] = $value;
283+
});
284+
285+
return new static($data);
286+
}
287+
}

0 commit comments

Comments
 (0)