Skip to content

Commit

Permalink
Merge pull request #1 from cmatosbc/adding
Browse files Browse the repository at this point in the history
Enhancements.
  • Loading branch information
cmatosbc authored Dec 16, 2024
2 parents 94af226 + d5db6ca commit 47640e1
Show file tree
Hide file tree
Showing 9 changed files with 1,022 additions and 720 deletions.
777 changes: 147 additions & 630 deletions README.md

Large diffs are not rendered by default.

172 changes: 172 additions & 0 deletions src/MultiMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
<?php

namespace Daedalus;

use InvalidArgumentException;
use Countable;

/**
* A map implementation that allows multiple values to be associated with a single key.
*/
class MultiMap implements Countable
{
private array $map = [];
private bool $allowDuplicates;

/**
* Create a new MultiMap instance
*
* @param bool $allowDuplicates Whether to allow duplicate values for the same key
*/
public function __construct(bool $allowDuplicates = true)
{
$this->allowDuplicates = $allowDuplicates;
}

/**
* Add a value to the collection of values associated with a key
*
* @param mixed $key The key
* @param mixed $value The value to add
* @return bool True if the value was added, false if it was a duplicate and duplicates are not allowed
*/
public function put($key, $value): bool
{
if (!isset($this->map[$key])) {
$this->map[$key] = [];
}

if (!$this->allowDuplicates && in_array($value, $this->map[$key], true)) {
return false;
}

$this->map[$key][] = $value;
return true;
}

/**
* Get all values associated with a key
*
* @param mixed $key The key to look up
* @return array Array of values associated with the key
*/
public function get($key): array
{
return $this->map[$key] ?? [];
}

/**
* Remove a specific value from a key's collection
*
* @param mixed $key The key
* @param mixed $value The value to remove
* @return bool True if the value was removed, false if it wasn't found
*/
public function removeValue($key, $value): bool
{
if (!isset($this->map[$key])) {
return false;
}

$index = array_search($value, $this->map[$key], true);
if ($index === false) {
return false;
}

array_splice($this->map[$key], $index, 1);
if (empty($this->map[$key])) {
unset($this->map[$key]);
}
return true;
}

/**
* Remove all values associated with a key
*
* @param mixed $key The key to remove
* @return array The removed values
*/
public function removeAll($key): array
{
$values = $this->get($key);
unset($this->map[$key]);
return $values;
}

/**
* Get all keys that have at least one value
*
* @return array
*/
public function keys(): array
{
return array_keys($this->map);
}

/**
* Get all values in the multimap
*
* @return array
*/
public function values(): array
{
return array_merge(...array_values($this->map));
}

/**
* Check if the multimap contains a key
*
* @param mixed $key The key to check
* @return bool
*/
public function containsKey($key): bool
{
return isset($this->map[$key]);
}

/**
* Check if the multimap contains a value for any key
*
* @param mixed $value The value to check
* @return bool
*/
public function containsValue($value): bool
{
foreach ($this->map as $values) {
if (in_array($value, $values, true)) {
return true;
}
}
return false;
}

/**
* Get the total number of values across all keys
*
* @return int
*/
public function count(): int
{
return array_sum(array_map('count', $this->map));
}

/**
* Get the number of keys in the multimap
*
* @return int
*/
public function keyCount(): int
{
return count($this->map);
}

/**
* Clear all entries from the multimap
*
* @return void
*/
public function clear(): void
{
$this->map = [];
}
}
147 changes: 147 additions & 0 deletions src/SortedMap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php

namespace Daedalus;

use InvalidArgumentException;

/**
* A map implementation that keeps its keys in sorted order.
* Keys must be comparable (strings, numbers, or objects implementing Comparable).
*/
class SortedMap
{
private array $entries = [];
private $comparator;

/**
* Create a new SortedMap instance
*
* @param callable|null $comparator Optional custom comparison function
*/
public function __construct(?callable $comparator = null)
{
$this->comparator = $comparator ?? fn($a, $b) => $a <=> $b;
}

/**
* Put a key-value pair into the map
*
* @param mixed $key The key
* @param mixed $value The value
* @return void
*/
public function put($key, $value): void
{
$this->entries[$key] = $value;
$this->sort();
}

/**
* Get a value by key
*
* @param mixed $key The key to look up
* @return mixed|null The value, or null if not found
*/
public function get($key)
{
return $this->entries[$key] ?? null;
}

/**
* Remove a key-value pair from the map
*
* @param mixed $key The key to remove
* @return void
*/
public function remove($key): void
{
unset($this->entries[$key]);
}

/**
* Get all keys in sorted order
*
* @return array
*/
public function keys(): array
{
return array_keys($this->entries);
}

/**
* Get all values in order corresponding to sorted keys
*
* @return array
*/
public function values(): array
{
return array_values($this->entries);
}

/**
* Get the first key in the sorted map
*
* @return mixed|null
*/
public function firstKey()
{
if (empty($this->entries)) {
return null;
}
$keys = $this->keys();
return reset($keys);
}

/**
* Get the last key in the sorted map
*
* @return mixed|null
*/
public function lastKey()
{
if (empty($this->entries)) {
return null;
}
$keys = $this->keys();
return end($keys);
}

/**
* Check if the map contains a key
*
* @param mixed $key The key to check
* @return bool
*/
public function containsKey($key): bool
{
return array_key_exists($key, $this->entries);
}

/**
* Get the number of entries in the map
*
* @return int
*/
public function count(): int
{
return count($this->entries);
}

/**
* Clear all entries from the map
*
* @return void
*/
public function clear(): void
{
$this->entries = [];
}

/**
* Sort the internal entries array using the comparator
*/
private function sort(): void
{
uksort($this->entries, $this->comparator);
}
}
Loading

0 comments on commit 47640e1

Please sign in to comment.