【问题标题】:Is there Java HashMap equivalent in PHP?PHP中是否有等效的Java HashMap?
【发布时间】:2011-10-14 01:24:01
【问题描述】:

我需要类似于 Java 中的 HashMap 的 PHP 对象,但是当我用 Google 搜索时没有找到,所以如果有人知道我可以如何在 PHP 中模仿 HashMaps,将不胜感激。

【问题讨论】:

  • 哈希映射对你来说有什么特点?
  • 我需要键/值对,并且我需要从映射中获取键作为数组。
  • $keys = array_keys($array);(另请参阅下面的 sushils 答案)
  • 数组实际上是 PHP 中唯一的数据结构(如果您不将类/对象视为数据结构)。它提供了键/值结构,您可以使用array_keys 轻松获取键。如果你愿意,你可以编写一个包装类。

标签: php hashmap


【解决方案1】:

PHP 中的数组可以具有键值结构。

【讨论】:

  • @Gabi:如果它像鸭子一样走路,像鸭子一样游泳,像鸭子一样嘎嘎叫…… PHP 手册说:PHP 中的数组实际上是一个有序映射。
  • @Felix Kling AFAIK PHP 数组没有 O(1) 查找/插入/删除,所以它们不像 hashmaps 那样嘎嘎作响
  • @Gabi Purcaru 相关:Time/Space complexity of PHP Array.
  • @Gabi:PHP中数组的内部实现哈希映射。
  • 这仍然不是 HashMap,因为我不能使用对象作为键 :(.
【解决方案2】:

根据您的需要,您可能对 SPL 对象存储类感兴趣。

http://php.net/manual/en/class.splobjectstorage.php

它可以让你使用对象作为键,有一个接口来计数,获取哈希和其他好处。

$s = new SplObjectStorage;
$o1 = new stdClass;
$o2 = new stdClass;
$o2->foo = 'bar';

$s[$o1] = 'baz';
$s[$o2] = 'bingo';

echo $s[$o1]; // 'baz'
echo $s[$o2]; // 'bingo'

【讨论】:

  • 这个。 boztek 你被低估了
  • SplObjectStorage 有一些缺点:当您使用 foreach 时,键是整数。而且您无法从中检索键和值列表。就我而言,我决定使用实现 ArrayAccess、Iterator 和 Countable 的自定义类。
  • 最佳答案在这里
【解决方案3】:

使用 O(1) 读取复杂度在 PHP 中创建类似 HashMap 的 Java。

打开一个phpsh终端:

php> $myhashmap = array();
php> $myhashmap['mykey1'] = 'myvalue1';
php> $myhashmap['mykey2'] = 'myvalue2';
php> echo $myhashmap['mykey2'];
myvalue2

在这种情况下,$myhashmap['mykey2'] 的复杂性似乎是常数时间 O(1),这意味着随着 $myhasmap 的大小接近无穷大,检索给定键的值所需的时间保持不变.

证明 php 数组读取的时间是常数:

通过 PHP 解释器运行:

php> for($x = 0; $x < 1000000000; $x++){
 ... $myhashmap[$x] = $x . " derp";
 ... }

循环添加了 10 亿个键/值,将它们全部添加到 hashmap 大约需要 2 分钟,这可能会耗尽你的内存。

然后看看做一次查找需要多长时间:

php> system('date +%N');echo "  " . $myhashmap[10333] . "  ";system('date +%N');
786946389  10333 derp  789008364

那么 PHP 数组映射查找有多快?

10333 是我们查找的密钥。 100 万纳秒 == 1 毫秒。从键中获取值所需的时间为 206 万纳秒或大约 2 毫秒。如果数组为空,则大约相同的时间。这对我来说似乎是恒定的时间。

【讨论】:

  • Not constant time...假设底层实现是一个基于数组的hashmap,那么由于需要处理冲突,你能做的最好的就是O(log n)冲突存储为自平衡树(例如哈希图的 Java 实现),但甚至可能存储在链表(链接)中,这给出了 O(n) 的最坏情况。这对于插入和查找都是如此,但平均情况将接近 O(1)...
  • 对于消耗一台计算机的整个内存(例如 8 GB)的数据集大小,查找时间是几毫秒。所以它“非常接近恒定时间,它基本上是恒定时间”,但是如果你想在数学上正确地将 100 亿个盒子执行到无穷大,那就是 O(n log n)。我也可以挑剔。 :) 我在这里使用恒定时间的意思是“这不会是你的瓶颈兄弟,甚至不要绊倒狗”。
  • 我同意,它可能不会成为瓶颈,因为所有操作的 O(log n) 仍然非常快。关键是获得恒定时间散列的唯一方法是散列函数是否完美,并且不存在碰撞。如果不完美,你得到的最好的就是 O(log n)。但是,根据:phpinternalsbook.com/hashtables/basic_structure.html php 使用链接,最坏的情况是 O(N)。我不知道是不是这样,因为我希望使用实现 log n 的解决方案,例如自平衡树,但如果是这样的话,O(N) 和 O(1 ) 不是微不足道的。
【解决方案4】:
$fruits = array (
    "fruits"  => array("a" => "Orange", "b" => "Banana", "c" => "Apple"),
    "numbers" => array(1, 2, 3, 4, 5, 6),
    "holes"   => array("first", 5 => "second", "third")
);

echo $fruits["fruits"]["b"]

输出“香蕉”

取自http://in2.php.net/manual/en/function.array.php

【讨论】:

  • 如果我想声明一个 空数组 并做如下赋值:"fruits" =&gt; array("a" =&gt; "Orange", "b" =&gt; "Banana", "c" =&gt; "Apple") after?
  • @Diego $fruits = array(); $fruits['fruits'] = array('a' =&gt; 'Orange',...); ...实际上,您甚至可以立即执行此操作:$fruits['fruits']['a'] = 'Orange'; $fruits['holes']['first'] = 5; $fruits['numbers'][] = 1; 您甚至不需要使用array() 创建任何数组。
【解决方案5】:

HashMap 也适用于字符串和整数以外的键,读取复杂度为 O(1)(取决于您自己的哈希函数的质量)。

您可以自己制作一个简单的 hashMap。 hashMap 所做的是使用哈希作为索引/键将项目存储在数组中。哈希函数偶尔会发生冲突(不经常发生,但它们可能会发生),因此您必须在 hashMap 中为一个条目存储多个项目。这么简单就是一个hashMap:

class IEqualityComparer {
    public function equals($x, $y) {
        throw new Exception("Not implemented!");
    }
    public function getHashCode($obj) {
        throw new Exception("Not implemented!");
    }
}

class HashMap {
    private $map = array();
    private $comparer;

    public function __construct(IEqualityComparer $keyComparer) {
        $this->comparer = $keyComparer;
    }

    public function has($key) {
        $hash = $this->comparer->getHashCode($key);

        if (!isset($this->map[$hash])) {
            return false;
        }

        foreach ($this->map[$hash] as $item) {
            if ($this->comparer->equals($item['key'], $key)) {
                return true;
            }
        }

        return false;
    }

    public function get($key) {
        $hash = $this->comparer->getHashCode($key);

        if (!isset($this->map[$hash])) {
            return false;
        }

        foreach ($this->map[$hash] as $item) {
            if ($this->comparer->equals($item['key'], $key)) {
                return $item['value'];
            }
        }

        return false;
    }

    public function del($key) {
        $hash = $this->comparer->getHashCode($key);

        if (!isset($this->map[$hash])) {
            return false;
        }

        foreach ($this->map[$hash] as $index => $item) {
            if ($this->comparer->equals($item['key'], $key)) {
                unset($this->map[$hash][$index]);
                if (count($this->map[$hash]) == 0)
                    unset($this->map[$hash]);

                return true;
            }
        }

        return false;
    }

    public function put($key, $value) {
        $hash = $this->comparer->getHashCode($key);

        if (!isset($this->map[$hash])) {
            $this->map[$hash] = array();
        }

        $newItem = array('key' => $key, 'value' => $value);        

        foreach ($this->map[$hash] as $index => $item) {
            if ($this->comparer->equals($item['key'], $key)) {
                $this->map[$hash][$index] = $newItem;
                return;
            }
        }

        $this->map[$hash][] = $newItem;
    }
}

为了让它起作用,你还需要一个哈希函数作为你的键和一个比较器来判断相等(如果你只有几个项目或出于其他原因不需要速度,你可以让哈希函数返回 0;所有项目将放在同一个桶中,您将获得 O(N) 复杂度)

这是一个例子:

class IntArrayComparer extends IEqualityComparer {
    public function equals($x, $y) {
        if (count($x) !== count($y))
            return false;

        foreach ($x as $key => $value) {
            if (!isset($y[$key]) || $y[$key] !== $value)
                return false;
        }

        return true;
    }

    public function getHashCode($obj) {
        $hash = 0;
        foreach ($obj as $key => $value)
            $hash ^= $key ^ $value;

        return $hash;
    }
}

$hashmap = new HashMap(new IntArrayComparer());

for ($i = 0; $i < 10; $i++) {
    for ($j = 0; $j < 10; $j++) {
        $hashmap->put(array($i, $j), $i * 10 + $j);
    }
}

echo $hashmap->get(array(3, 7)) . "<br/>";
echo $hashmap->get(array(5, 1)) . "<br/>";

echo ($hashmap->has(array(8, 4))? 'true': 'false') . "<br/>";
echo ($hashmap->has(array(-1, 9))? 'true': 'false') . "<br/>";
echo ($hashmap->has(array(6))? 'true': 'false') . "<br/>";
echo ($hashmap->has(array(1, 2, 3))? 'true': 'false') . "<br/>";

$hashmap->del(array(8, 4));
echo ($hashmap->has(array(8, 4))? 'true': 'false') . "<br/>";

作为输出给出:

37
51
true
false
false
false
false

【讨论】:

  • IEqualityComparer 应该是 interface 这里
【解决方案6】:

您可以在 php.ini 中为此创建一个自定义 HashMap 类。 示例如下所示,包含基本的 HashMap 属性,例如 get 和 set。

class HashMap{

        public $arr;

        function init() {

            function populate() {
                return null;
            }
            
            // change to 999 for efficiency
            $this->arr = array_map('populate', range(0, 9));

            return $this->arr;

        }
        
        function get_hash($key) {
            $hash = 0;

            for ($i=0; $i < strlen($key) ; $i++) { 
                $hash += ord($key[$i]);
            }
            
            // arr index starts from 0
            $hash_idx = $hash % (count($this->arr) - 1); 
            return $hash_idx;
            
        }

        function add($key, $value) {
            $idx = $this->get_hash($key);
            
            if ($this->arr[$idx] == null) {
                $this->arr[$idx] = [$value];
            } else{

                $found = false;

                $content = $this->arr[$idx];
                
                $content_idx = 0;
                foreach ($content as $item) {

                    // checking if they have same number of streams
                    if ($item == $value) {

                        $content[$content_idx] = [$value];
                        $found = true;
                        break;

                    }
                    
                    $content_idx++;
                }

                if (!$found) {
                    // $value is already an array
                    array_push($content, $value);

                    // updating the array
                    $this->arr[$idx] = $content;
                }

            }

            return $this->arr;

        }

        function get($key) {

            $idx = $this->get_hash($key);
            $content = $this->arr[$idx];

            foreach ($content as $item) {
                if ($item[1] == $key) {
                    return $item;
                    break;
                }
            }
                
        }

    }

希望对你有用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-18
    • 1970-01-01
    • 2012-05-24
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2011-04-16
    相关资源
    最近更新 更多