在PHP中是否有等效的Java HashMap?


78

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


1
什么是您的哈希映射的特征?
菲利克斯·克林

1
我需要键/值对,并且需要从地图中以数组形式获取键。
新手

1
$keys = array_keys($array);(也可以在下面看到sushils的答案)
KingCrunch 2011年

数组实际上是PHP中唯一的数据结构(如果您不将类/对象视为数据结构)。它提供了一个键/值结构,您可以使用轻松获得键array_keys。您可以根据需要编写包装器类。
菲利克斯·克林

Answers:


93

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


64
@Gabi:如果它走路像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎... PHP手册说:PHP中的数组实际上是有序映射。
菲利克斯·克林

115
@Felix Kling AFAIK PHP数组没有O(1)查找/插入/删除,因此它们不像哈希图那样嘎嘎作响
Gabi Purcaru 2011年

14
@Gabi Purcaru相关信息:PHP Array的时间/空间复杂性
jensgram

20
@Gabi:PHP数组的内部实现哈希映射。
KingCrunch

4
这仍然不是HashMap,因为我不能将对象用作键:(
。– knub

37

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

http://php.net/manual/zh/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'

2
这个。boztek,您被低估了
CommaToast 2014年

SplObjectStorage有一些缺点:使用foreach时,键是整数。而且您无法从中检索键和值的列表。就我而言,我决定使用实现ArrayAccess,Iterator和Countable的自定义类。
carlosvini 2014年


最佳答案在这里
奥列格Abrazhaev

31

在PHP中用O(1)读取复杂性创建Java,例如HashMap。

打开一个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亿个键/值,大约需要2分钟才能将它们全部添加到哈希图中,这可能会耗尽您的内存。

然后查看进行查找需要多长时间:

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

那么,PHP数组映射查找的速度有多快?

10333是我们查找的关键。1百万纳秒== 1毫秒。从键获取值所花费的时间为206万纳秒(约2毫秒)。如果数组为空,则大约相同的时间。对我来说,这似乎是永恒的时间。


时间不是固定的……假设基础实现是基于数组的哈希图,则由于需要处理冲突,在将冲突存储为自平衡的情况下,您最好能做到O(log n)-树(例如哈希映射的Java实现),但甚至可能存储在链表(链接)中,这给出了O(n)的最坏情况。插入和查找均是如此,但平均大小写接近O(1)...
Daniel Valland

1
对于占用一台计算机整个内存(例如8 GB)的数据集大小,查找时间只有几毫秒。因此,它“非常接近恒定时间,基本上是恒定时间”,但是如果您想在数学上正确地将100亿个盒子装到无限大的地方,则为O(n log n)。我也可以挑剔。:)我在这里使用固定时间意味着“这不会成为您的瓶颈兄弟,甚至不要绊倒狗”。
Eric Leschinski

我同意,这可能不会成为瓶颈,因为所有操作的O(log n)仍然非常快。关键是,获得恒定时间散列的唯一方法是散列函数是否完美,并且没有大肠菌。如果不是完美的,则得到的最好结果是O(log n)。但是,根据:phpinternalsbook.com/hashtables/basic_structure.html php使用链接,这种链接的最坏情况是O(N)。我不知道是这种情况,因为我希望使用实现log n的解决方案,例如自平衡树,但是如果是这种情况,则O(N)和O(1 )并非无关紧要。
Daniel Valland

14
$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" => array("a" => "Orange", "b" => "Banana", "c" => "Apple")
diegoaguilar 2013年

2
@Diego $fruits = array(); $fruits['fruits'] = array('a' => 'Orange',...);...实际上,您甚至可以立即进行此操作:$fruits['fruits']['a'] = 'Orange'; $fruits['holes']['first'] = 5; $fruits['numbers'][] = 1;您甚至不必一定要使用创建任何数组array()
zamnuts

10

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

2
IEqualityComparer应该在interface这里
vp_arth
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.