1
|
|
|
<?php |
2
|
|
|
namespace Ds; |
3
|
|
|
|
4
|
|
|
use OutOfBoundsException; |
5
|
|
|
use OutOfRangeException; |
6
|
|
|
use Traversable; |
7
|
|
|
use UnderflowException; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class Map |
11
|
|
|
* |
12
|
|
|
* @package Ds |
13
|
|
|
*/ |
14
|
|
|
final class Map implements \IteratorAggregate, \ArrayAccess, Collection |
15
|
|
|
{ |
16
|
|
|
use Traits\Collection; |
17
|
|
|
use Traits\SquaredCapacity; |
18
|
|
|
|
19
|
|
|
const MIN_CAPACITY = 8; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* @var Pair[] |
23
|
|
|
*/ |
24
|
|
|
private $internal = []; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Creates an instance using the values of an array or Traversable object. |
28
|
|
|
* |
29
|
|
|
* @param array|\Traversable|null $values |
30
|
|
|
*/ |
31
|
1018 |
|
public function __construct($values = null) |
32
|
|
|
{ |
33
|
1018 |
|
if (func_num_args()) { |
34
|
525 |
|
$this->putAll($values); |
35
|
|
|
} |
36
|
1018 |
|
} |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Updates all values by applying a callback function to each value. |
40
|
|
|
* |
41
|
|
|
* @param callable $callback Accepts two arguments: key and value, should |
42
|
|
|
* return what the updated value will be. |
43
|
|
|
*/ |
44
|
5 |
|
public function apply(callable $callback) |
45
|
|
|
{ |
46
|
5 |
|
foreach ($this->internal as &$pair) { |
47
|
4 |
|
$pair->value = $callback($pair->key, $pair->value); |
48
|
|
|
} |
49
|
2 |
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* @inheritDoc |
53
|
|
|
*/ |
54
|
4 |
|
public function clear() |
55
|
|
|
{ |
56
|
4 |
|
$this->internal = []; |
57
|
4 |
|
$this->capacity = self::MIN_CAPACITY; |
58
|
4 |
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Return the first Pair from the Map |
62
|
|
|
* |
63
|
|
|
* @return Pair |
64
|
|
|
* |
65
|
|
|
* @throws UnderflowException |
66
|
|
|
*/ |
67
|
8 |
|
public function first(): Pair |
68
|
|
|
{ |
69
|
8 |
|
if ($this->isEmpty()) { |
70
|
2 |
|
throw new UnderflowException(); |
71
|
|
|
} |
72
|
|
|
|
73
|
6 |
|
return $this->internal[0]; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Return the last Pair from the Map |
78
|
|
|
* |
79
|
|
|
* @return Pair |
80
|
|
|
* |
81
|
|
|
* @throws UnderflowException |
82
|
|
|
*/ |
83
|
8 |
|
public function last(): Pair |
84
|
|
|
{ |
85
|
8 |
|
if ($this->isEmpty()) { |
86
|
2 |
|
throw new UnderflowException(); |
87
|
|
|
} |
88
|
|
|
|
89
|
6 |
|
return end($this->internal); |
90
|
|
|
} |
91
|
|
|
|
92
|
|
|
/** |
93
|
|
|
* Return the pair at a specified position in the Map |
94
|
|
|
* |
95
|
|
|
* @param int $position |
96
|
|
|
* |
97
|
|
|
* @return Pair |
98
|
|
|
* |
99
|
|
|
* @throws OutOfRangeException |
100
|
|
|
*/ |
101
|
37 |
|
public function skip(int $position): Pair |
102
|
|
|
{ |
103
|
37 |
|
if ($position < 0 || $position >= count($this->internal)) { |
104
|
13 |
|
throw new OutOfRangeException(); |
105
|
|
|
} |
106
|
|
|
|
107
|
24 |
|
return $this->internal[$position]->copy(); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
/** |
111
|
|
|
* Merge an array of values with the current Map |
112
|
|
|
* |
113
|
|
|
* @param array|\Traversable $values |
114
|
|
|
* |
115
|
|
|
* @return Map |
116
|
|
|
*/ |
117
|
44 |
|
public function merge($values): Map |
118
|
|
|
{ |
119
|
44 |
|
$merged = new self($this); |
120
|
44 |
|
$merged->putAll($values); |
121
|
|
|
|
122
|
44 |
|
return $merged; |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Intersect |
127
|
|
|
* |
128
|
|
|
* @param Map $map |
129
|
|
|
* |
130
|
|
|
* @return Map |
131
|
|
|
*/ |
132
|
24 |
|
public function intersect(Map $map): Map |
133
|
|
|
{ |
134
|
|
|
return $this->filter(function($key) use ($map) { |
135
|
20 |
|
return $map->hasKey($key); |
136
|
24 |
|
}); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* Diff |
141
|
|
|
* |
142
|
|
|
* @param Map $map |
143
|
|
|
* |
144
|
|
|
* @return Map |
145
|
|
|
*/ |
146
|
24 |
|
public function diff(Map $map): Map |
147
|
|
|
{ |
148
|
|
|
return $this->filter(function($key) use ($map) { |
149
|
20 |
|
return ! $map->hasKey($key); |
150
|
24 |
|
}); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
/** |
154
|
|
|
* Identical |
155
|
|
|
* |
156
|
|
|
* @param mixed $a |
157
|
|
|
* @param mixed $b |
158
|
|
|
* |
159
|
|
|
* @return bool |
160
|
|
|
*/ |
161
|
621 |
|
private function keysAreEqual($a, $b): bool |
162
|
|
|
{ |
163
|
621 |
|
if (is_object($a) && $a instanceof Hashable) { |
164
|
18 |
|
return get_class($a) === get_class($b) && $a->equals($b); |
165
|
|
|
} |
166
|
|
|
|
167
|
617 |
|
return $a === $b; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @param $key |
172
|
|
|
* |
173
|
|
|
* @return Pair|null |
174
|
|
|
*/ |
175
|
701 |
|
private function lookupKey($key) |
176
|
|
|
{ |
177
|
701 |
|
foreach ($this->internal as $pair) { |
178
|
614 |
|
if ($this->keysAreEqual($pair->key, $key)) { |
179
|
614 |
|
return $pair; |
180
|
|
|
} |
181
|
|
|
} |
182
|
701 |
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* @param $value |
186
|
|
|
* |
187
|
|
|
* @return Pair|null |
188
|
|
|
*/ |
189
|
5 |
|
private function lookupValue($value) |
190
|
|
|
{ |
191
|
5 |
|
foreach ($this->internal as $pair) { |
192
|
4 |
|
if ($pair->value === $value) { |
193
|
4 |
|
return $pair; |
194
|
|
|
} |
195
|
|
|
} |
196
|
3 |
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Returns whether an association a given key exists. |
200
|
|
|
* |
201
|
|
|
* @param mixed $key |
202
|
|
|
* |
203
|
|
|
* @return bool |
204
|
|
|
*/ |
205
|
69 |
|
public function hasKey($key): bool |
206
|
|
|
{ |
207
|
69 |
|
return $this->lookupKey($key) !== null; |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Returns whether an association for a given value exists. |
212
|
|
|
* |
213
|
|
|
* @param mixed $value |
214
|
|
|
* |
215
|
|
|
* @return bool |
216
|
|
|
*/ |
217
|
5 |
|
public function hasValue($value): bool |
218
|
|
|
{ |
219
|
5 |
|
return $this->lookupValue($value) !== null; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* @inheritDoc |
224
|
|
|
*/ |
225
|
710 |
|
public function count(): int |
226
|
|
|
{ |
227
|
710 |
|
return count($this->internal); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Returns a new map containing only the values for which a predicate |
232
|
|
|
* returns true. A boolean test will be used if a predicate is not provided. |
233
|
|
|
* |
234
|
|
|
* @param callable|null $callback Accepts a key and a value, and returns: |
235
|
|
|
* true : include the value, |
236
|
|
|
* false: skip the value. |
237
|
|
|
* |
238
|
|
|
* @return Map |
239
|
|
|
*/ |
240
|
76 |
|
public function filter(callable $callback = null): Map |
241
|
|
|
{ |
242
|
76 |
|
$filtered = new self(); |
243
|
|
|
|
244
|
76 |
|
foreach ($this as $key => $value) { |
245
|
63 |
|
if ($callback ? $callback($key, $value) : $value) { |
246
|
62 |
|
$filtered->put($key, $value); |
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
250
|
73 |
|
return $filtered; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Returns the value associated with a key, or an optional default if the |
255
|
|
|
* key is not associated with a value. |
256
|
|
|
* |
257
|
|
|
* @param mixed $key |
258
|
|
|
* @param mixed $default |
259
|
|
|
* |
260
|
|
|
* @return mixed The associated value or fallback default if provided. |
261
|
|
|
* |
262
|
|
|
* @throws OutOfBoundsException if no default was provided and the key is |
263
|
|
|
* not associated with a value. |
264
|
|
|
*/ |
265
|
33 |
|
public function get($key, $default = null) |
266
|
|
|
{ |
267
|
33 |
|
if (($pair = $this->lookupKey($key))) { |
268
|
29 |
|
return $pair->value; |
269
|
|
|
} |
270
|
|
|
|
271
|
4 |
|
if (func_num_args() === 1) { |
272
|
1 |
|
throw new OutOfBoundsException(); |
273
|
|
|
} |
274
|
|
|
|
275
|
3 |
|
return $default; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
/** |
279
|
|
|
* Returns a set of all the keys in the map. |
280
|
|
|
* |
281
|
|
|
* @return Set |
282
|
|
|
*/ |
283
|
37 |
|
public function keys(): Set |
284
|
|
|
{ |
285
|
37 |
|
$set = new Set(); |
286
|
|
|
|
287
|
37 |
|
foreach ($this->internal as $pair) { |
288
|
19 |
|
$set->add($pair->key); |
289
|
|
|
} |
290
|
|
|
|
291
|
37 |
|
return $set; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Returns a new map using the results of applying a callback to each value. |
296
|
|
|
* |
297
|
|
|
* The keys will be equal in both maps. |
298
|
|
|
* |
299
|
|
|
* @param callable $callback Accepts two arguments: key and value, should |
300
|
|
|
* return what the updated value will be. |
301
|
|
|
* |
302
|
|
|
* @return Map |
303
|
|
|
*/ |
304
|
5 |
|
public function map(callable $callback): Map |
305
|
|
|
{ |
306
|
5 |
|
$mapped = new self(); |
307
|
|
|
|
308
|
5 |
|
foreach ($this->internal as $pair) { |
309
|
4 |
|
$mapped[$pair->key] = $callback($pair->key, $pair->value); |
310
|
|
|
} |
311
|
|
|
|
312
|
2 |
|
return $mapped; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
/** |
316
|
|
|
* Returns a sequence of pairs representing all associations. |
317
|
|
|
* |
318
|
|
|
* @return Sequence |
319
|
|
|
*/ |
320
|
7 |
|
public function pairs(): Sequence |
321
|
|
|
{ |
322
|
7 |
|
$sequence = new Vector(); |
323
|
|
|
|
324
|
7 |
|
foreach ($this->internal as $pair) { |
325
|
5 |
|
$sequence[] = $pair->copy(); |
326
|
|
|
} |
327
|
|
|
|
328
|
7 |
|
return $sequence; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
/** |
332
|
|
|
* Associates a key with a value, replacing a previous association if there |
333
|
|
|
* was one. |
334
|
|
|
* |
335
|
|
|
* @param mixed $key |
336
|
|
|
* @param mixed $value |
337
|
|
|
*/ |
338
|
693 |
|
public function put($key, $value) |
339
|
|
|
{ |
340
|
693 |
|
$pair = $this->lookupKey($key); |
341
|
|
|
|
342
|
693 |
|
if ($pair) { |
343
|
64 |
|
$pair->value = $value; |
344
|
|
|
|
345
|
|
|
} else { |
346
|
693 |
|
$this->adjustCapacity(); |
347
|
693 |
|
$this->internal[] = new Pair($key, $value); |
348
|
|
|
} |
349
|
693 |
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Creates associations for all keys and corresponding values of either an |
353
|
|
|
* array or iterable object. |
354
|
|
|
* |
355
|
|
|
* @param \Traversable|array $values |
356
|
|
|
*/ |
357
|
525 |
|
public function putAll($values) |
358
|
|
|
{ |
359
|
525 |
|
foreach ($values as $key => $value) { |
360
|
324 |
|
$this->put($key, $value); |
361
|
|
|
} |
362
|
525 |
|
} |
363
|
|
|
|
364
|
|
|
/** |
365
|
|
|
* Iteratively reduces the map to a single value using a callback. |
366
|
|
|
* |
367
|
|
|
* @param callable $callback Accepts the carry, key, and value, and |
368
|
|
|
* returns an updated carry value. |
369
|
|
|
* |
370
|
|
|
* @param mixed|null $initial Optional initial carry value. |
371
|
|
|
* |
372
|
|
|
* @return mixed The carry value of the final iteration, or the initial |
373
|
|
|
* value if the map was empty. |
374
|
|
|
*/ |
375
|
8 |
|
public function reduce(callable $callback, $initial = null) |
376
|
|
|
{ |
377
|
8 |
|
$carry = $initial; |
378
|
|
|
|
379
|
8 |
|
foreach ($this->internal as $pair) { |
380
|
6 |
|
$carry = $callback($carry, $pair->key, $pair->value); |
381
|
|
|
} |
382
|
|
|
|
383
|
6 |
|
return $carry; |
384
|
|
|
} |
385
|
|
|
|
386
|
|
|
/** |
387
|
|
|
* |
388
|
|
|
*/ |
389
|
28 |
|
private function delete(int $position) |
390
|
|
|
{ |
391
|
28 |
|
$pair = $this->internal[$position]; |
392
|
28 |
|
$value = $pair->value; |
393
|
|
|
|
394
|
28 |
|
array_splice($this->internal, $position, 1, null); |
395
|
|
|
|
396
|
28 |
|
$this->adjustCapacity(); |
397
|
28 |
|
return $value; |
398
|
|
|
} |
399
|
|
|
|
400
|
|
|
/** |
401
|
|
|
* Removes a key's association from the map and returns the associated value |
402
|
|
|
* or a provided default if provided. |
403
|
|
|
* |
404
|
|
|
* @param mixed $key |
405
|
|
|
* @param mixed $default |
406
|
|
|
* |
407
|
|
|
* @return mixed The associated value or fallback default if provided. |
408
|
|
|
* |
409
|
|
|
* @throws \OutOfBoundsException if no default was provided and the key is |
410
|
|
|
* not associated with a value. |
411
|
|
|
*/ |
412
|
34 |
|
public function remove($key, $default = null) |
413
|
|
|
{ |
414
|
34 |
|
foreach ($this->internal as $position => $pair) { |
415
|
30 |
|
if ($this->keysAreEqual($pair->key, $key)) { |
416
|
30 |
|
return $this->delete($position); |
417
|
|
|
} |
418
|
|
|
} |
419
|
|
|
|
420
|
|
|
// Check if a default was provided |
421
|
9 |
|
if (func_num_args() === 1) { |
422
|
1 |
|
throw new \OutOfBoundsException(); |
423
|
|
|
} |
424
|
|
|
|
425
|
8 |
|
return $default; |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
/** |
429
|
|
|
* Returns a reversed copy of the map. |
430
|
|
|
*/ |
431
|
15 |
|
public function reverse() |
432
|
|
|
{ |
433
|
15 |
|
$this->internal = array_reverse($this->internal); |
434
|
15 |
|
} |
435
|
|
|
|
436
|
|
|
/** |
437
|
|
|
* Returns a reversed copy of the map. |
438
|
|
|
*/ |
439
|
|
|
public function reversed(): Map |
440
|
|
|
{ |
441
|
|
|
$reversed = new self(); |
442
|
|
|
$reversed->internal = array_reverse($this->internal); |
443
|
|
|
|
444
|
|
|
return $reversed; |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
/** |
448
|
|
|
* Returns a sub-sequence of a given length starting at a specified offset. |
449
|
|
|
* |
450
|
|
|
* @param int $offset If the offset is non-negative, the map will |
451
|
|
|
* start at that offset in the map. If offset is |
452
|
|
|
* negative, the map will start that far from the |
453
|
|
|
* end. |
454
|
|
|
* |
455
|
|
|
* @param int|null $length If a length is given and is positive, the |
456
|
|
|
* resulting set will have up to that many pairs in |
457
|
|
|
* it. If the requested length results in an |
458
|
|
|
* overflow, only pairs up to the end of the map |
459
|
|
|
* will be included. |
460
|
|
|
* |
461
|
|
|
* If a length is given and is negative, the map |
462
|
|
|
* will stop that many pairs from the end. |
463
|
|
|
* |
464
|
|
|
* If a length is not provided, the resulting map |
465
|
|
|
* will contains all pairs between the offset and |
466
|
|
|
* the end of the map. |
467
|
|
|
* |
468
|
|
|
* @return Map |
469
|
|
|
*/ |
470
|
400 |
|
public function slice(int $offset, int $length = null): Map |
471
|
|
|
{ |
472
|
400 |
|
$map = new self(); |
473
|
|
|
|
474
|
400 |
|
if (func_num_args() === 1) { |
475
|
100 |
|
$slice = array_slice($this->internal, $offset); |
476
|
|
|
} else { |
477
|
300 |
|
$slice = array_slice($this->internal, $offset, $length); |
478
|
|
|
} |
479
|
|
|
|
480
|
400 |
|
foreach ($slice as $pair) { |
481
|
140 |
|
$map->put($pair->key, $pair->value); |
482
|
|
|
} |
483
|
|
|
|
484
|
400 |
|
return $map; |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Sorts the map in-place, based on an optional callable comparator. |
489
|
|
|
* |
490
|
|
|
* The map will be sorted by value. |
491
|
|
|
* |
492
|
|
|
* @param callable|null $comparator Accepts two values to be compared. |
493
|
|
|
*/ |
494
|
6 |
View Code Duplication |
public function sort(callable $comparator = null) |
|
|
|
|
495
|
|
|
{ |
496
|
6 |
|
if ($comparator) { |
497
|
|
|
usort($this->internal, function($a, $b) use ($comparator) { |
498
|
2 |
|
return $comparator($a->value, $b->value); |
499
|
3 |
|
}); |
500
|
|
|
|
501
|
|
|
} else { |
502
|
|
|
usort($this->internal, function($a, $b) { |
503
|
2 |
|
return $a->value <=> $b->value; |
504
|
3 |
|
}); |
505
|
|
|
} |
506
|
6 |
|
} |
507
|
|
|
|
508
|
|
|
/** |
509
|
|
|
* Returns a sorted copy of the map, based on an optional callable |
510
|
|
|
* comparator. The map will be sorted by value. |
511
|
|
|
* |
512
|
|
|
* @param callable|null $comparator Accepts two values to be compared. |
513
|
|
|
* |
514
|
|
|
* @return Map |
515
|
|
|
*/ |
516
|
6 |
View Code Duplication |
public function sorted(callable $comparator = null): Map |
|
|
|
|
517
|
|
|
{ |
518
|
6 |
|
$sorted = new self($this); |
519
|
|
|
|
520
|
6 |
|
if ($comparator) { |
521
|
|
|
usort($sorted->internal, function($a, $b) use ($comparator) { |
522
|
2 |
|
return $comparator($a->value, $b->value); |
523
|
3 |
|
}); |
524
|
|
|
|
525
|
|
|
} else { |
526
|
|
|
usort($sorted->internal, function($a, $b) { |
527
|
2 |
|
return $a->value <=> $b->value; |
528
|
3 |
|
}); |
529
|
|
|
} |
530
|
|
|
|
531
|
6 |
|
return $sorted; |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Sorts the map in-place, based on an optional callable comparator. |
536
|
|
|
* |
537
|
|
|
* The map will be sorted by key. |
538
|
|
|
* |
539
|
|
|
* @param callable|null $comparator Accepts two keys to be compared. |
540
|
|
|
*/ |
541
|
10 |
View Code Duplication |
public function ksort(callable $comparator = null) |
|
|
|
|
542
|
|
|
{ |
543
|
10 |
|
if ($comparator) { |
544
|
|
|
usort($this->internal, function($a, $b) use ($comparator) { |
545
|
4 |
|
return $comparator($a->key, $b->key); |
546
|
5 |
|
}); |
547
|
|
|
|
548
|
|
|
} else { |
549
|
|
|
usort($this->internal, function($a, $b) { |
550
|
4 |
|
return $a->key <=> $b->key; |
551
|
5 |
|
}); |
552
|
|
|
} |
553
|
10 |
|
} |
554
|
|
|
|
555
|
|
|
/** |
556
|
|
|
* Returns a sorted copy of the map, based on an optional callable |
557
|
|
|
* comparator. The map will be sorted by key. |
558
|
|
|
* |
559
|
|
|
* @param callable|null $comparator Accepts two keys to be compared. |
560
|
|
|
* |
561
|
|
|
* @return Map |
562
|
|
|
*/ |
563
|
6 |
View Code Duplication |
public function ksorted(callable $comparator = null): Map |
|
|
|
|
564
|
|
|
{ |
565
|
6 |
|
$sorted = $this->copy(); |
566
|
|
|
|
567
|
6 |
|
if ($comparator) { |
568
|
|
|
usort($sorted->internal, function($a, $b) use ($comparator) { |
|
|
|
|
569
|
2 |
|
return $comparator($a->key, $b->key); |
570
|
3 |
|
}); |
571
|
|
|
|
572
|
|
|
} else { |
573
|
|
|
usort($sorted->internal, function($a, $b) { |
|
|
|
|
574
|
2 |
|
return $a->key <=> $b->key; |
575
|
3 |
|
}); |
576
|
|
|
} |
577
|
|
|
|
578
|
6 |
|
return $sorted; |
579
|
|
|
} |
580
|
|
|
|
581
|
|
|
/** |
582
|
|
|
* Returns the sum of all values in the map. |
583
|
|
|
* |
584
|
|
|
* @return int|float The sum of all the values in the map. |
585
|
|
|
*/ |
586
|
7 |
|
public function sum() |
587
|
|
|
{ |
588
|
7 |
|
return $this->values()->sum(); |
589
|
|
|
} |
590
|
|
|
|
591
|
|
|
/** |
592
|
|
|
* @inheritDoc |
593
|
|
|
*/ |
594
|
409 |
|
public function toArray(): array |
595
|
|
|
{ |
596
|
409 |
|
$array = []; |
597
|
|
|
|
598
|
409 |
|
foreach ($this->internal as $pair) { |
599
|
252 |
|
$array[$pair->key] = $pair->value; |
600
|
|
|
} |
601
|
|
|
|
602
|
408 |
|
return $array; |
603
|
|
|
} |
604
|
|
|
|
605
|
|
|
/** |
606
|
|
|
* Returns a sequence of all the associated values in the Map. |
607
|
|
|
* |
608
|
|
|
* @return Sequence |
609
|
|
|
*/ |
610
|
10 |
|
public function values(): Sequence |
611
|
|
|
{ |
612
|
10 |
|
$sequence = new Vector(); |
613
|
|
|
|
614
|
10 |
|
foreach ($this->internal as $pair) { |
615
|
8 |
|
$sequence->push($pair->value); |
616
|
|
|
} |
617
|
|
|
|
618
|
10 |
|
return $sequence; |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
/** |
622
|
|
|
* |
623
|
|
|
* |
624
|
|
|
* @return \Ds\Map |
625
|
|
|
*/ |
626
|
12 |
|
public function union(Map $map): Map |
627
|
|
|
{ |
628
|
12 |
|
return $this->merge($map); |
629
|
|
|
} |
630
|
|
|
|
631
|
|
|
/** |
632
|
|
|
* XOR |
633
|
|
|
* |
634
|
|
|
* @param Map $map |
635
|
|
|
* |
636
|
|
|
* @return Map |
637
|
|
|
*/ |
638
|
|
|
public function xor(Map $map): Map |
639
|
|
|
{ |
640
|
20 |
|
return $this->merge($map)->filter(function($key) use ($map) { |
641
|
16 |
|
return $this->hasKey($key) ^ $map->hasKey($key); |
642
|
20 |
|
}); |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
/** |
646
|
|
|
* Get iterator |
647
|
|
|
*/ |
648
|
535 |
|
public function getIterator() |
649
|
|
|
{ |
650
|
535 |
|
foreach ($this->internal as $pair) { |
651
|
381 |
|
yield $pair->key => $pair->value; |
652
|
|
|
} |
653
|
532 |
|
} |
654
|
|
|
|
655
|
|
|
/** |
656
|
|
|
* Debug Info |
657
|
|
|
*/ |
658
|
3 |
|
public function __debugInfo() |
659
|
|
|
{ |
660
|
3 |
|
return $this->pairs()->toArray(); |
661
|
|
|
} |
662
|
|
|
|
663
|
|
|
/** |
664
|
|
|
* @inheritdoc |
665
|
|
|
*/ |
666
|
8 |
|
public function offsetSet($offset, $value) |
667
|
|
|
{ |
668
|
8 |
|
$this->put($offset, $value); |
669
|
8 |
|
} |
670
|
|
|
|
671
|
|
|
/** |
672
|
|
|
* @inheritdoc |
673
|
|
|
* |
674
|
|
|
* @throws OutOfBoundsException |
675
|
|
|
*/ |
676
|
17 |
|
public function &offsetGet($offset) |
677
|
|
|
{ |
678
|
17 |
|
$pair = $this->lookupKey($offset); |
679
|
|
|
|
680
|
17 |
|
if ($pair) { |
681
|
17 |
|
return $pair->value; |
682
|
|
|
} |
683
|
|
|
|
684
|
|
|
throw new OutOfBoundsException(); |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
/** |
688
|
|
|
* @inheritdoc |
689
|
|
|
*/ |
690
|
4 |
|
public function offsetUnset($offset) |
691
|
|
|
{ |
692
|
4 |
|
$this->remove($offset, null); |
693
|
4 |
|
} |
694
|
|
|
|
695
|
|
|
/** |
696
|
|
|
* @inheritdoc |
697
|
|
|
*/ |
698
|
20 |
|
public function offsetExists($offset) |
699
|
|
|
{ |
700
|
20 |
|
return $this->get($offset, null) !== null; |
701
|
|
|
} |
702
|
|
|
} |
703
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.