Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
54 / 54 |
|
100.00% |
12 / 12 |
CRAP | |
100.00% |
1 / 1 |
ArrayOperation | |
100.00% |
54 / 54 |
|
100.00% |
12 / 12 |
45 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
set | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getKeys | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getValues | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getElements | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
get | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
5 | |||
getFirst | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
9 | |||
getLast | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
9 | |||
filterByElement | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
6 | |||
filterByKey | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
filterByValue | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
filter | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
5 |
1 | <?php |
2 | |
3 | /** |
4 | * @license MIT |
5 | * @author hazuki3417<hazuki3417@gmail.com> |
6 | * @copyright 2024 hazuki3417 all rights reserved. |
7 | */ |
8 | |
9 | namespace Selen\Array; |
10 | |
11 | use ArrayIterator; |
12 | |
13 | /** |
14 | * 配列の操作を提供するクラスです。 |
15 | */ |
16 | class ArrayOperation |
17 | { |
18 | public const SEARCH_CONDITION_KEY = 'key'; |
19 | public const SEARCH_CONDITION_VALUE = 'value'; |
20 | public const SEARCH_CONDITION_ELEMENT = 'element'; |
21 | public const RETURN_CONDITION_KEY = 'key'; |
22 | public const RETURN_CONDITION_VALUE = 'value'; |
23 | public const RETURN_CONDITION_ELEMENT = 'element'; |
24 | |
25 | /** @var ArrayIterator<int|string,mixed> イテレータクラスのインスタンス */ |
26 | private ArrayIterator $arrayIterator; |
27 | |
28 | /** |
29 | * 新しいArrayOperationインスタンスを生成します。 |
30 | * |
31 | * @param ArrayIterator<int|string,mixed> $arrayIterator イテレータクラスのインスタンスを渡します |
32 | */ |
33 | public function __construct(ArrayIterator $arrayIterator) |
34 | { |
35 | $this->arrayIterator = $arrayIterator; |
36 | } |
37 | |
38 | /** |
39 | * 新しいArrayOperationインスタンスを生成します。 |
40 | * |
41 | * @param array<mixed,mixed> $value 配列を渡します |
42 | */ |
43 | public static function set(array $value): ArrayOperation |
44 | { |
45 | return new self(new ArrayIterator($value)); |
46 | } |
47 | |
48 | /** |
49 | * 配列のキーを取得します |
50 | * |
51 | * @return array<int,mixed> 配列のキーを返します |
52 | */ |
53 | public function getKeys(): array |
54 | { |
55 | return array_keys($this->arrayIterator->getArrayCopy()); |
56 | } |
57 | |
58 | /** |
59 | * 配列の値を取得します |
60 | * |
61 | * @return array<int,mixed> 配列の値を返します |
62 | */ |
63 | public function getValues(): array |
64 | { |
65 | return array_values($this->arrayIterator->getArrayCopy()); |
66 | } |
67 | |
68 | /** |
69 | * 配列の要素を取得します |
70 | * |
71 | * @return array<mixed,mixed> 配列の要素を返します |
72 | */ |
73 | public function getElements(): array |
74 | { |
75 | return $this->arrayIterator->getArrayCopy(); |
76 | } |
77 | |
78 | /** |
79 | * 指定した条件に一致する要素を取得します |
80 | * |
81 | * @param string $returnCondition 取得条件を指定します |
82 | * |
83 | * @return array<mixed,mixed> 配列を返します |
84 | */ |
85 | public function get(string $returnCondition = self::RETURN_CONDITION_ELEMENT): array |
86 | { |
87 | switch ($returnCondition) { |
88 | case self::RETURN_CONDITION_KEY: |
89 | return $this->getKeys(); |
90 | case self::RETURN_CONDITION_VALUE: |
91 | return $this->getValues(); |
92 | case self::RETURN_CONDITION_ELEMENT: |
93 | return $this->getElements(); |
94 | default: |
95 | break; |
96 | } |
97 | throw new \InvalidArgumentException('invalid return condition.'); |
98 | } |
99 | |
100 | /** |
101 | * 配列の先頭要素を取得します |
102 | * |
103 | * @param string $searchCondition 検索条件を指定します |
104 | * |
105 | * @return array<mixed,mixed> 配列を返します |
106 | */ |
107 | public function getFirst(string $searchCondition = self::SEARCH_CONDITION_ELEMENT): array |
108 | { |
109 | $isEmpty = $this->arrayIterator->count() === 0; |
110 | |
111 | if (!$isEmpty) { |
112 | $this->arrayIterator->rewind(); |
113 | } |
114 | |
115 | switch ($searchCondition) { |
116 | case self::SEARCH_CONDITION_KEY: |
117 | return $isEmpty ? [] : [$this->arrayIterator->key()]; |
118 | case self::SEARCH_CONDITION_VALUE: |
119 | return $isEmpty ? [] : [$this->arrayIterator->current()]; |
120 | case self::SEARCH_CONDITION_ELEMENT: |
121 | return $isEmpty ? [] : [$this->arrayIterator->key() => $this->arrayIterator->current()]; |
122 | default: |
123 | break; |
124 | } |
125 | throw new \InvalidArgumentException('invalid search condition.'); |
126 | } |
127 | |
128 | /** |
129 | * 配列の末尾要素を取得します |
130 | * |
131 | * @param string $searchCondition 検索条件を指定します |
132 | * |
133 | * @return array<mixed,mixed> 配列を返します |
134 | */ |
135 | public function getLast(string $searchCondition = self::SEARCH_CONDITION_ELEMENT): array |
136 | { |
137 | $isEmpty = $this->arrayIterator->count() === 0; |
138 | |
139 | if (!$isEmpty) { |
140 | $lastIndex = $this->arrayIterator->count() - 1; |
141 | $this->arrayIterator->seek($lastIndex); |
142 | } |
143 | |
144 | switch ($searchCondition) { |
145 | case self::SEARCH_CONDITION_KEY: |
146 | return $isEmpty ? [] : [$this->arrayIterator->key()]; |
147 | case self::SEARCH_CONDITION_VALUE: |
148 | return $isEmpty ? [] : [$this->arrayIterator->current()]; |
149 | case self::SEARCH_CONDITION_ELEMENT: |
150 | return $isEmpty ? [] : [$this->arrayIterator->key() => $this->arrayIterator->current()]; |
151 | default: |
152 | break; |
153 | } |
154 | throw new \InvalidArgumentException('invalid search condition.'); |
155 | } |
156 | |
157 | /** |
158 | * 指定した要素に一致する要素を抽出します |
159 | * |
160 | * @param array<int,array<string|int,mixed>> $elements 検索対象の要素を指定します |
161 | */ |
162 | public function filterByElement(array $elements): ArrayOperation |
163 | { |
164 | for ($this->arrayIterator->rewind(); $this->arrayIterator->valid();) { |
165 | $isElementMatch = false; |
166 | |
167 | foreach ($elements as $elementKey => $elementValue) { |
168 | $isKeyMatch = $elementKey === $this->arrayIterator->key(); |
169 | $isValueMatch = $elementValue === $this->arrayIterator->current(); |
170 | |
171 | if ($isKeyMatch && $isValueMatch) { |
172 | $isElementMatch = true; |
173 | break; |
174 | } |
175 | } |
176 | |
177 | $isElementMatch ? |
178 | $this->arrayIterator->next() : |
179 | $this->arrayIterator->offsetUnset($this->arrayIterator->key()); |
180 | } |
181 | return $this; |
182 | } |
183 | |
184 | /** |
185 | * 指定したkeyに一致する要素を抽出します |
186 | * |
187 | * @param string|int $key 検索対象のkeyを指定します |
188 | */ |
189 | public function filterByKey(string|int ...$key): ArrayOperation |
190 | { |
191 | for ($this->arrayIterator->rewind(); $this->arrayIterator->valid();) { |
192 | in_array($this->arrayIterator->key(), $key, true) ? |
193 | $this->arrayIterator->next() : |
194 | $this->arrayIterator->offsetUnset($this->arrayIterator->key()); |
195 | } |
196 | return $this; |
197 | } |
198 | |
199 | /** |
200 | * 指定したvalueに一致する要素を抽出します |
201 | * |
202 | * @param mixed $value 検索対象のvalueを指定します |
203 | */ |
204 | public function filterByValue(mixed ...$value): ArrayOperation |
205 | { |
206 | for ($this->arrayIterator->rewind(); $this->arrayIterator->valid();) { |
207 | in_array($this->arrayIterator->current(), $value, true) ? |
208 | $this->arrayIterator->next() : |
209 | $this->arrayIterator->offsetUnset($this->arrayIterator->key()); |
210 | } |
211 | return $this; |
212 | } |
213 | |
214 | /** |
215 | * 指定した条件に一致する要素を抽出します |
216 | * |
217 | * @param array<mixed,mixed> $needle 検索対象の要素を指定します |
218 | * @param string $searchCondition 検索条件を指定します |
219 | */ |
220 | public function filter(array $needle, string $searchCondition = self::SEARCH_CONDITION_ELEMENT): ArrayOperation |
221 | { |
222 | switch ($searchCondition) { |
223 | case self::SEARCH_CONDITION_KEY: |
224 | return $this->filterByKey(...$needle); |
225 | case self::SEARCH_CONDITION_VALUE: |
226 | return $this->filterByValue(...$needle); |
227 | case self::SEARCH_CONDITION_ELEMENT: |
228 | return $this->filterByElement($needle); |
229 | default: |
230 | break; |
231 | } |
232 | throw new \InvalidArgumentException('invalid search condition.'); |
233 | } |
234 | } |