Skip to content

Commit 47640e1

Browse files
authored
Merge pull request #1 from cmatosbc/adding
Enhancements.
2 parents 94af226 + d5db6ca commit 47640e1

File tree

9 files changed

+1022
-720
lines changed

9 files changed

+1022
-720
lines changed

README.md

Lines changed: 147 additions & 630 deletions
Large diffs are not rendered by default.

src/MultiMap.php

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
namespace Daedalus;
4+
5+
use InvalidArgumentException;
6+
use Countable;
7+
8+
/**
9+
* A map implementation that allows multiple values to be associated with a single key.
10+
*/
11+
class MultiMap implements Countable
12+
{
13+
private array $map = [];
14+
private bool $allowDuplicates;
15+
16+
/**
17+
* Create a new MultiMap instance
18+
*
19+
* @param bool $allowDuplicates Whether to allow duplicate values for the same key
20+
*/
21+
public function __construct(bool $allowDuplicates = true)
22+
{
23+
$this->allowDuplicates = $allowDuplicates;
24+
}
25+
26+
/**
27+
* Add a value to the collection of values associated with a key
28+
*
29+
* @param mixed $key The key
30+
* @param mixed $value The value to add
31+
* @return bool True if the value was added, false if it was a duplicate and duplicates are not allowed
32+
*/
33+
public function put($key, $value): bool
34+
{
35+
if (!isset($this->map[$key])) {
36+
$this->map[$key] = [];
37+
}
38+
39+
if (!$this->allowDuplicates && in_array($value, $this->map[$key], true)) {
40+
return false;
41+
}
42+
43+
$this->map[$key][] = $value;
44+
return true;
45+
}
46+
47+
/**
48+
* Get all values associated with a key
49+
*
50+
* @param mixed $key The key to look up
51+
* @return array Array of values associated with the key
52+
*/
53+
public function get($key): array
54+
{
55+
return $this->map[$key] ?? [];
56+
}
57+
58+
/**
59+
* Remove a specific value from a key's collection
60+
*
61+
* @param mixed $key The key
62+
* @param mixed $value The value to remove
63+
* @return bool True if the value was removed, false if it wasn't found
64+
*/
65+
public function removeValue($key, $value): bool
66+
{
67+
if (!isset($this->map[$key])) {
68+
return false;
69+
}
70+
71+
$index = array_search($value, $this->map[$key], true);
72+
if ($index === false) {
73+
return false;
74+
}
75+
76+
array_splice($this->map[$key], $index, 1);
77+
if (empty($this->map[$key])) {
78+
unset($this->map[$key]);
79+
}
80+
return true;
81+
}
82+
83+
/**
84+
* Remove all values associated with a key
85+
*
86+
* @param mixed $key The key to remove
87+
* @return array The removed values
88+
*/
89+
public function removeAll($key): array
90+
{
91+
$values = $this->get($key);
92+
unset($this->map[$key]);
93+
return $values;
94+
}
95+
96+
/**
97+
* Get all keys that have at least one value
98+
*
99+
* @return array
100+
*/
101+
public function keys(): array
102+
{
103+
return array_keys($this->map);
104+
}
105+
106+
/**
107+
* Get all values in the multimap
108+
*
109+
* @return array
110+
*/
111+
public function values(): array
112+
{
113+
return array_merge(...array_values($this->map));
114+
}
115+
116+
/**
117+
* Check if the multimap contains a key
118+
*
119+
* @param mixed $key The key to check
120+
* @return bool
121+
*/
122+
public function containsKey($key): bool
123+
{
124+
return isset($this->map[$key]);
125+
}
126+
127+
/**
128+
* Check if the multimap contains a value for any key
129+
*
130+
* @param mixed $value The value to check
131+
* @return bool
132+
*/
133+
public function containsValue($value): bool
134+
{
135+
foreach ($this->map as $values) {
136+
if (in_array($value, $values, true)) {
137+
return true;
138+
}
139+
}
140+
return false;
141+
}
142+
143+
/**
144+
* Get the total number of values across all keys
145+
*
146+
* @return int
147+
*/
148+
public function count(): int
149+
{
150+
return array_sum(array_map('count', $this->map));
151+
}
152+
153+
/**
154+
* Get the number of keys in the multimap
155+
*
156+
* @return int
157+
*/
158+
public function keyCount(): int
159+
{
160+
return count($this->map);
161+
}
162+
163+
/**
164+
* Clear all entries from the multimap
165+
*
166+
* @return void
167+
*/
168+
public function clear(): void
169+
{
170+
$this->map = [];
171+
}
172+
}

src/SortedMap.php

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
<?php
2+
3+
namespace Daedalus;
4+
5+
use InvalidArgumentException;
6+
7+
/**
8+
* A map implementation that keeps its keys in sorted order.
9+
* Keys must be comparable (strings, numbers, or objects implementing Comparable).
10+
*/
11+
class SortedMap
12+
{
13+
private array $entries = [];
14+
private $comparator;
15+
16+
/**
17+
* Create a new SortedMap instance
18+
*
19+
* @param callable|null $comparator Optional custom comparison function
20+
*/
21+
public function __construct(?callable $comparator = null)
22+
{
23+
$this->comparator = $comparator ?? fn($a, $b) => $a <=> $b;
24+
}
25+
26+
/**
27+
* Put a key-value pair into the map
28+
*
29+
* @param mixed $key The key
30+
* @param mixed $value The value
31+
* @return void
32+
*/
33+
public function put($key, $value): void
34+
{
35+
$this->entries[$key] = $value;
36+
$this->sort();
37+
}
38+
39+
/**
40+
* Get a value by key
41+
*
42+
* @param mixed $key The key to look up
43+
* @return mixed|null The value, or null if not found
44+
*/
45+
public function get($key)
46+
{
47+
return $this->entries[$key] ?? null;
48+
}
49+
50+
/**
51+
* Remove a key-value pair from the map
52+
*
53+
* @param mixed $key The key to remove
54+
* @return void
55+
*/
56+
public function remove($key): void
57+
{
58+
unset($this->entries[$key]);
59+
}
60+
61+
/**
62+
* Get all keys in sorted order
63+
*
64+
* @return array
65+
*/
66+
public function keys(): array
67+
{
68+
return array_keys($this->entries);
69+
}
70+
71+
/**
72+
* Get all values in order corresponding to sorted keys
73+
*
74+
* @return array
75+
*/
76+
public function values(): array
77+
{
78+
return array_values($this->entries);
79+
}
80+
81+
/**
82+
* Get the first key in the sorted map
83+
*
84+
* @return mixed|null
85+
*/
86+
public function firstKey()
87+
{
88+
if (empty($this->entries)) {
89+
return null;
90+
}
91+
$keys = $this->keys();
92+
return reset($keys);
93+
}
94+
95+
/**
96+
* Get the last key in the sorted map
97+
*
98+
* @return mixed|null
99+
*/
100+
public function lastKey()
101+
{
102+
if (empty($this->entries)) {
103+
return null;
104+
}
105+
$keys = $this->keys();
106+
return end($keys);
107+
}
108+
109+
/**
110+
* Check if the map contains a key
111+
*
112+
* @param mixed $key The key to check
113+
* @return bool
114+
*/
115+
public function containsKey($key): bool
116+
{
117+
return array_key_exists($key, $this->entries);
118+
}
119+
120+
/**
121+
* Get the number of entries in the map
122+
*
123+
* @return int
124+
*/
125+
public function count(): int
126+
{
127+
return count($this->entries);
128+
}
129+
130+
/**
131+
* Clear all entries from the map
132+
*
133+
* @return void
134+
*/
135+
public function clear(): void
136+
{
137+
$this->entries = [];
138+
}
139+
140+
/**
141+
* Sort the internal entries array using the comparator
142+
*/
143+
private function sort(): void
144+
{
145+
uksort($this->entries, $this->comparator);
146+
}
147+
}

0 commit comments

Comments
 (0)