tonix-tuft / linked-hash-map
如果PHP没有关联数组,我将如何实现一个链表哈希表
v1.3.0
2021-07-17 09:35 UTC
Requires
- php: ^7.0
- tonix-tuft/fun: ^1.3
- tonix-tuft/int-hash: ^1.0
- tonix-tuft/php-declarative-factory: ^1.3
- tonix-tuft/php-utils: ^1.15
Requires (Dev)
- phpunit/phpunit: ^8.5
This package is auto-updated.
Last update: 2024-09-17 16:26:59 UTC
README
如果PHP没有关联数组,我将如何实现一个链表哈希表
安装
使用 Composer
composer require tonix-tuft/linked-hash-map
用法
此映射实现了 ArrayAccess 接口以及 Iterator 和 Countable 接口,因此可以作为内置PHP数组使用
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map['abc'] = 'string (abc)'; $map['abcdef'] = 'string (abcdef)'; $map[123] = 'int (123)'; var_dump(count($map)); // 3 foreach ($map as $key => $value) { var_dump($key, $value); }
使用任何PHP数据类型作为键
此映射允许使用任何PHP类型作为键(即,甚至可以将数组或对象用作键)
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map[true] = 'bool (true)'; $map[false] = 'bool (false)'; $map[32441] = 'int (32441)'; $map[-32441] = 'int (-32441)'; $map[2147483647] = 'int (2147483647)'; $map[-2147483648] = 'int (-2147483648)'; $map[PHP_INT_MAX - 100] = 'int (PHP_INT_MAX - 100)'; $map[PHP_INT_MIN] = 'int (PHP_INT_MIN)'; $map[0.5] = 'float/double (0.5)'; $map[-0.5] = 'float/double (-0.5)'; $map[123891.73] = 'float/double (123891.73)'; $map[-123891.73] = 'float/double (-123891.73)'; $map[PHP_INT_MAX + 10] = 'float/double (PHP_INT_MAX + 10)'; $map[PHP_INT_MIN - 10] = 'float/double (PHP_INT_MIN - 10)'; $map['abc'] = 'string (abc)'; $map["abcdef"] = "string (abcdef)"; $map['hfudsh873hu2ifl'] = "string (hfudsh873hu2ifl)"; $map["The quick brown fox jumps over the lazy dog"] = 'string (The quick brown fox jumps over the lazy dog)'; $map[[1, 2, 3]] = 'array ([1, 2, 3])'; $map[['a', 'b', 'c']] = "array (['a', 'b', 'c'])"; $map[[1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]]] = "array ([1, 'a', false, 5, true, [1, 2, 3, ['f', 5, []]]])"; $arrayKey = [ 1, 'a', false, 5, true, [1, 2, 3, ['f', 5, [new stdClass(), new stdClass()]]], new ArrayIterator(), ]; $map[$arrayKey] = "array ([1, 'a', false, 5, true, [1, 2, 3, ['f', 5, [new stdClass(), new stdClass()]]], new ArrayIterator()])"; $stdClassObj = new stdClass(); $map[$stdClassObj] = "object (new stdClass())"; $arrayIterator = new ArrayIterator(); $map[$arrayIterator] = "object (new ArrayIterator())"; class A { } $objA = new A(); $map[$objA] = "object (new A())"; $fp = fopen(__DIR__ . '/private_local_file', 'w'); $map[$fp] = "resource (fopen())"; $ch = curl_init(); $map[$ch] = "resource (curl_init())"; // All the values can be retrieved later using the corresponding key, e.g.: var_dump($map[[1, 2, 3]]); // "array ([1, 2, 3])" var_dump($map[$objA]); // "object (new A())" var_dump($map[$ch]); // "resource (curl_init())"
此映射与内置PHP数组之间的差异和相似之处
此映射与内置PHP数组之间的差异以及任何相似之处如下
- 使用此映射时,可以使用任何PHP数据类型作为键(
bool
,int
,float/double
,string
,array
,object
,callable
,iterable
,resource
)。这也意味着例如浮点数1.5
将作为键使用,而在内置PHP数组中,1.5
将被 类型转换 为1
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map[1.5] = 'A value for key 1.5'; var_dump($map[1.5]); // "A value for key 1.5" var_dump($map[1]); // NULL $arr = []; $arr[1.5] = 'A value'; // [1 => "A value"]; var_dump($arr[1.5]); // "A value" var_dump($arr[1]); // "A value"
- 在设置
LinkedHashMap::INSERT_MODE_PREPEND
标志(使用setInsertMode
方法)时,此映射允许预添加而不是追加
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map->setInsertMode(LinkedHashMap::INSERT_MODE_PREPEND); // Defaults to `LinkedHashMap::INSERT_MODE_APPEND` $map['a'] = 1; $map['b'] = 2; foreach ($map as $key => $value) { var_dump($key, $value); } // 'b', 2 // 'a', 1
- 此映射还允许设置循环顺序(迭代顺序),是正常顺序(
LinkedHashMap::LOOP_ORDER_NORMAL
,默认值)还是反向顺序(LinkedHashMap::LOOP_ORDER_REVERSE
)(使用setLoopOrder
方法)
<?php use LinkedHashMap\LinkedHashMap; // Example 1: $map = new LinkedHashMap(); $map->setLoopOrder(LinkedHashMap::LOOP_ORDER_REVERSE); // Defaults to `LinkedHashMap::LOOP_ORDER_NORMAL` $map['a'] = 1; $map['b'] = 2; foreach ($map as $key => $value) { var_dump($key, $value); } // 'b', 2 // 'a', 1 // Example 2: $map = new LinkedHashMap(); $map->setInsertMode(LinkedHashMap::INSERT_MODE_PREPEND); // Defaults to `LinkedHashMap::INSERT_MODE_APPEND` $map->setLoopOrder(LinkedHashMap::LOOP_ORDER_REVERSE); // Defaults to `LinkedHashMap::LOOP_ORDER_NORMAL` $map['a'] = 1; $map['b'] = 2; foreach ($map as $key => $value) { var_dump($key, $value); } // 'a', 1 // 'b', 2
- 追加/预添加到映射的工作方式与内置PHP数组相同(创建一个位置索引(一个
int 或 integer string >= 0
)或内部增加迄今为止使用的最高位置索引)。访问未知索引不会触发/发出通知(仅返回NULL
)
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map[] = 'Value for index 0'; $map[] = 'Value for index 1'; $map[1234] = 'Value for index 1234'; $map[] = 'Value for index 1235'; var_dump($map[0]); // "Value for index 0" var_dump($map[1]); // "Value for index 1" var_dump($map[2]); // NULL (no E_NOTICE/E_USER_NOTICE) var_dump($map[1234]); // "Value for index 1234" var_dump($map[1235]); // "Value for index 1235" $arr = []; $arr[] = 'Value for index 0'; $arr[] = 'Value for index 1'; $arr[1234] = 'Value for index 1234'; $arr[] = 'Value for index 1235'; var_dump($arr[0]); // "Value for index 0" var_dump($arr[1]); // "Value for index 1" var_dump($arr[2]); // NULL (emits E_NOTICE) var_dump($arr[1234]); // "Value for index 1234" var_dump($arr[1235]); // "Value for index 1235"
- 因为 ArrayAccess::offsetSet 不允许区分
NULL
和追加/预添加操作($map[] = 'A value'
),所以不能使用NULL
作为键。使用NULL
作为键将被视为追加/预添加操作。由于内置PHP数组将NULL
映射到空字符串''
,这不应该是一个问题
<?php use LinkedHashMap\LinkedHashMap; $map = new LinkedHashMap(); $map[null] = 'Value for index 0'; $map[null] = 'Value for index 1'; $map[1234] = 'Value for index 1234'; $map[null] = 'Value for index 1235'; var_dump($map[0]); // "Value for index 0" var_dump($map[1]); // "Value for index 1" var_dump($map[1234]); // "Value for index 1234" var_dump($map[1235]); // "Value for index 1235" var_dump($map[null]); // NULL var_dump($map['']); // NULL $arr = []; $arr[null] = 'Value for index 0'; $arr[null] = 'Value for index 1'; $arr[1234] = 'Value for index 1234'; $arr[null] = 'Value for index 1235'; var_dump($arr[0]); // NULL (emits E_NOTICE) var_dump($arr[1]); // NULL (emits E_NOTICE) var_dump($arr[1234]); // "Value for index 1234" var_dump($arr[1235]); // NULL (emits E_NOTICE) var_dump($arr[null]); // "Value for index 1235" var_dump($arr['']); // "Value for index 1235"
使用自定义哈希码
内部,该映射使用 int-hash 包计算给定键的哈希值,以检索相应的值。如果键是实现了 LinkedHashMap\HashCodeInterface
接口的类的实例,则将调用其 hashCode
方法,并使用返回的哈希码(一个整数)代替
<?php use LinkedHashMap\LinkedHashMap; use LinkedHashMap\HashCodeInterface; class ClassWithCustomHashCode implements HashCodeInterface { /** * @var int */ protected $propertyA; /** * @var int */ protected $propertyB; public function __construct() { $this->propertyA = rand(0, 100000); $this->propertyB = rand(0, 100000); } // ... /** * {@inheritdoc} */ public function hashCode() { // Compute the hash code somehow... $prime = 31; $hash = 1; $hash = $prime * $hash + $this->propertyA; $hash = $prime * $hash + $this->propertyB; return $hash; } } $map = new LinkedHashMap(); $obj1 = new ClassWithCustomHashCode(); $obj2 = new ClassWithCustomHashCode(); $map[$obj1] = "A value"; $map[$obj2] = "Another value"; var_dump($map[$obj1]); // "A value" var_dump($map[$obj2]); // "Another value"
许可
MIT © Anton Bagdatyev (Tonix)