【问题标题】:Determine whether an array is associative (hash) or not [duplicate]确定数组是否是关联的(散列)
【发布时间】:2011-08-25 04:50:28
【问题描述】:

我希望能够将数组传递给函数,并根据它是“列表”样式数组还是“散列”样式数组让函数表现不同。例如:

myfunc(array("One", "Two", "Three")); // works
myfunc(array(1=>"One", 2=>"Two", 3=>"Three")); also works, but understands it's a hash

可能会输出如下内容:

One, Two, Three
1=One, 2=Two, 3=Three

ie:当函数“检测到”它被传递一个散列而不是一个数组时,它会做一些不同的事情。你能说我来自 Perl 背景,其中 %hashes 是来自 @arrays 的不同引用吗?

我相信我的示例很重要,因为我们不能只测试键是否为数字,因为您很可能在哈希中使用数字键。

我特别希望避免使用 myfunc(array(array(1=>"One"), array(2=>"Two"), array(3=>"Three"))) 的混乱构造

【问题讨论】:

  • 寻找这样的东西? stackoverflow.com/questions/173400/…
  • 有趣的问题。不幸的是,PHP 无法区分 array('a','b','c')array(0=>'a',1=>'b',2=>'c')...
  • PHP 将始终将数字键 array("1" => "1") 存储为整数。检测不出来。您只能探测不断增长的键以区分真实列表和索引数组。
  • 正确。不幸的是,它不能区分“简单”数组和以数字字符串为键的数组(请参阅我的回答)。

标签: php arrays hash


【解决方案1】:

直接从 kohana 框架中提取出来。

public static function is_assoc(array $array)
{
    // Keys of the array
    $keys = array_keys($array);

    // If the array keys of the keys match the keys, then the array must
    // not be associative (e.g. the keys array looked like {0:0, 1:1...}).
    return array_keys($keys) !== $keys;
}

【讨论】:

  • 确实很好。我仍然相信这一点......但它在我的代码中有效,所以谢谢!
  • 这对于已过滤的非关联数组失败,例如 [5 => 'foo']。
  • array_keys($arr) !== range(0, count($arr) - 1) as stackoverflow.com/a/173479/287948 ,
  • [0 => 'a', 2 => 'b', 3=>'c'] 使用此方法返回 true
  • 也被 Laravel 框架使用。 (在 Illuminate\Support\Arr 类中)
【解决方案2】:

This benchmark 提供了 3 种方法。

这是一个摘要,从最快到最慢排序。欲了解更多信息,请阅读完整的benchmark here

1.使用 array_values()

function($array) {
    return (array_values($array) !== $array);
}

2。使用 array_keys()

function($array){
    $array = array_keys($array); return ($array !== array_keys($array));
}

3.使用 array_filter()

function($array){
    return count(array_filter(array_keys($array), 'is_string')) > 0;
}

【讨论】:

  • 最好用实际的基准测试结果对此进行注释,以防链接失效。需要注意的是,array_filter 方法比其他方法几个数量级。
  • [0 => 'a', 2 => 'b', 3=>'c'] 在第一种情况下返回 true。
【解决方案3】:

从技术上讲,PHP 将所有数组都视为哈希,因此没有确切的方法来做到这一点。我相信你最好的选择是:

if (array_keys($array) === range(0, count($array) - 1)) {
   //it is a hash
}

【讨论】:

  • 这是唯一发布的解决方案,所以我会接受它,尽管它的固有限制是不考虑非顺序数组索引。这个问题:stackoverflow.com/questions/173400/…有很多解决方案,没有一个是完美的。
【解决方案4】:

不,在以下情况下,PHP 不会区分键是数字字符串的数组和键是整数的数组:

$a = array("0"=>'a', "1"=>'b', "2"=>'c');
$b = array(0=>'a', 1=>'b', 2=>'c');

var_dump(array_keys($a), array_keys($b));

它输出:

array(3) {
    [0]=> int(0) [1]=> int(1) [2]=> int(2)
}
array(3) {
    [0]=> int(0) [1]=> int(1) [2]=> int(2)
}

(以上格式为便于阅读)

【讨论】:

    【解决方案5】:

    我的解决方案是获取如下数组的键并检查该键是否不是整数:

    private function is_hash($array) {
        foreach($array as $key => $value) {
            return ! is_int($key);
        }
        return false;
    }
    

    下面这样获取哈希数组的array_keys是错误的:

    array_keys(array(
           "abc" => "gfb",
           "bdc" => "dbc"
           )
    );
    

    将输出:

    array(
           0 => "abc",
           1 => "bdc"
    )
    

    因此,将其与评分最高的答案中提到的一系列数字进行比较并不是一个好主意。如果您尝试将键与范围进行比较,它总是会说它是一个哈希数组。

    【讨论】:

    • 带我了解你的功能,因为我缺少一些东西。您有一个 foreach 循环,但您在该循环的第一次迭代中返回!如果您只是返回第一个键是否为整数,那么循环的意义何在?也许您打算将标志设置为 true,然后在我们的循环中,如果它是整数,则将标志设置为 false?
    • 否则你总是得到一个整数值作为数组键,这就是为什么!
    • 这更接近真实的答案恕我直言。不过,汤姆·奥格(Tom Auger)有一点。我认为它更像是: private function is_hash($array) { foreach(array_keys($array) as $key) { if (is_int($key)) { return false; } } 返回真; }
    【解决方案6】:

    有点沮丧,试图写一个函数来处理所有的组合,一个想法在我脑海中点击:解析json_encode结果。

    当 json 字符串包含大括号时,它必须包含一个对象!

    当然,看了这里的解决方案后,我的有点好笑…… 无论如何,我想与社区分享它,只是为了从另一个角度(更“直观”)提出解决问题的尝试。

    
    function isAssociative(array $arr): bool
        {
            // consider empty, and [0, 1, 2, ...] sequential
            if(empty($arr) || array_is_list($arr)) {
                return false;
            }
    
            // first scenario:
            // [  1  => [*any*] ]
            // [ 'a' => [*any*] ]
            foreach ($arr as $key => $value) {
                if(is_array($value)) {
                    return true;
                }
            }
    
             // second scenario: read the json string
            $jsonNest = json_encode($arr, JSON_THROW_ON_ERROR);
    
            return str_contains($jsonNest, '{'); // {} assoc, [] sequential
        }
    

    注意事项

    php@8.1 为必填项,查看gist on github 包含此方法的单元测试 + Polyfills (php>=7.3)。

    我还测试了Hussard's posted solutionsAB 正在通过所有测试,C 无法识别:{"1":0,"2":1}

    基准

    Here json 解析比 B~200 毫秒,但仍比解决方案 C1.7 秒 >!

    你觉得这个版本怎么样?欢迎改进!

    【讨论】:

      猜你喜欢
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-03
      • 2017-03-03
      • 1970-01-01
      • 1970-01-01
      • 2013-07-04
      相关资源
      最近更新 更多