Last active
August 9, 2020 18:25
-
-
Save jcartledge/5963823 to your computer and use it in GitHub Desktop.
PHP immutable set
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
function set() { | |
return new Set(func_get_args()); | |
} | |
class Set implements Countable, Iterator { | |
private $data = array(); | |
function __construct($data) { | |
$this->data = $this->unique_array($data); | |
} | |
/** Countable implementation **/ | |
function count () { return count($this->data); } | |
/** End Countable implementation **/ | |
/** Iterator implementation **/ | |
function current() { return current($this->data); } | |
function key () { return $this->hash(current($this->data)); } | |
function next () { next($this->data); return $this; } | |
function rewind () { reset($this->data); return $this; } | |
function valid () { return TRUE; } | |
/** End Iterator implementation **/ | |
/** "Mutation" operations return a new Set **/ | |
function map($fn) { | |
return new Set(array_map($fn, $this->data)); | |
} | |
function filter($fn) { | |
return new Set(array_filter($this->data, $fn)); | |
} | |
function append($value) { | |
return new Set(array_merge($this->data, func_get_args())); | |
} | |
function remove($value) { | |
$args = func_get_args(); | |
return $this->filter(function($x) use ($args) { | |
return !in_array($x, $args); | |
}); | |
} | |
function concat(Set $that) { | |
return new Set(array_merge($this->data), $that->as_array()); | |
} | |
/** End "Mutation" operations **/ | |
/** Boolean existence test **/ | |
function contains($value) { | |
return isset($this->data[$this->hash($value)]); | |
} | |
/** Native array **/ | |
function as_array() { | |
return array_values($this->data); | |
} | |
/** String for prettyprint **/ | |
function __toString() { | |
return sprintf('Set(%s)', implode(', ', | |
array_map(array($this, 'inspect'), $this->data) | |
)); | |
} | |
/** Key is hash of serialized value **/ | |
private function hash($data) { | |
return sha1(serialize($data)); | |
} | |
/** If we allow data to be passed in by reference (e.g nested arrays) **/ | |
/** Then there is a risk it will get modified from outside. **/ | |
private function copy($data) { | |
return unserialize(serialize($data)); | |
} | |
/** Convert an arbitrary array into one with unique values keyed on hash **/ | |
private function unique_array($arr) { | |
return array_combine( | |
array_map(array($this, 'hash'), $arr), | |
array_map(array($this, 'copy'), $arr) | |
); | |
} | |
/** Output variable type and value for prettyprint **/ | |
private function inspect($var) { | |
ob_start(); | |
var_dump($var); | |
return trim(ob_get_clean()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment