【问题标题】:PHP, in_array and fast searches (by the end) in arraysPHP,in_array 和数组中的快速搜索(到最后)
【发布时间】:2023-03-23 11:18:01
【问题描述】:

我怀疑在数组中进行快速搜索的更好方法是什么(我说的是一个具体案例)。

假设我有一个数组 L = [A, B, C](当我开始时)。在程序运行时,L 可能会增长(但到最后),我进行搜索的一种可能情况是 L = [A, B, C, D, E]。

事实是,当我在搜索时,我想要找到的值可能只有 D 和 E。现在我正在使用 find_array(elem, array),但是这个函数不能被“调整”来搜索从末尾开始并减少索引,我“害怕”对于所有搜索,函数 in_array 将检查所有具有较低索引的元素,然后才能找到我正在搜索的值。

¿还有另一个搜索功能更适合我的问题吗? ¿ in_array 函数内部如何工作?

提前致谢

【问题讨论】:

  • 附注:如果您事先知道您只会搜索新值?是否可以将这些新值存储在一个单独的数组中,该数组会更小,因此搜索速度更快? (如果 kenforces 的答案不适合您)
  • 我正在使用get_declared_classes()函数,我必须发现是否加载了特定的类...
  • php 手册没有提到函数 find_array()。所以我想知道您是否想要找到元素的键,或者您是否只想知道该元素是否存在。
  • 我只想验证它是否存在......但也许我所做的不是正确的方法。我将尝试使用 class_exists () 函数。

标签: php performance search


【解决方案1】:

我假设in_array 是从 0 到 n-1 的线性搜索。

最快的搜索是将值存储为键并使用array_key_exists

$a['foo'] = true;
$a['bar'] = true;

if (array_key_exists('foo', $a)) ...

但如果这不是一个选项,您可以很容易地为索引数组制作自己的:

function in_array_i($needle, array $a, $i = 0);
{
  $c = count($a);
  for (;$i < $c; ++$i)
    if ($a[$i] == $needle) return true;
  return false;
}

它将从 $i 开始,您可以跟踪自己以跳过第一个元素。

或者……

function in_array_i($needle, array $a, $i = 0);
{
  return in_array($needle, $i ? array_slice($a, $i) : $a);
}

您可以进行基准测试,看看哪个更快。

【讨论】:

  • @JordanArseno,是的,isset()array_key_exists() 快,但它确实为 null 值返回 false。 (在这种情况下并不重要。)也就是说,它们都是基本恒定的时间,而 in_array() 是 O(n) 并且当你到达一个大数组的末尾时性能明显更差。因此,当null 不是问题时,我更喜欢使用isset(),但主要的收获应该是in_array() 绝对是强制唯一性的错误方式。
【解决方案2】:

in_array 函数内部如何工作?

Internally in_array() 从数组的开头搜索到结尾。所以在你的情况下,这很慢。

根据数据的性质,您可以更改搜索策略。如果你只有非重复值并且所有值都是字符串或整数(不是NULL),一个常见的技巧是array_flip()这个数组很好用快速然后通过isset()检查数组哈希中是否有您的值作为键的条目:

  $array = array( ... non-duplicate string and integer values ... );
  $needle = 'find me!';
  $lookup = array_flip($array);
  $found = isset($lookup[$needle]) ? $lookup[$needle] : false;
  if (false === $found) {
    echo "Not found!\n";
  } else {
    echo "Found at {$found}!\n";
  }

如果不满足这些先决条件,您可以按照 konforce 的建议进行操作。

如果您的数据非常多,而且您不仅要从头或尾查看,您可能希望自己实现一种搜索算法,例如既不从头开始也不从尾开始,而是包装和/或从随机位置开始分配搜索时间。

此外,您可以在添加到数组时保持元素排序,然后使用拟合算法可以更快地搜索。

【讨论】:

    【解决方案3】:

    调整一个广泛的比较测试

    对于数字和字符串搜索,Kasim Kochkin 在GitHub 上发布,我发现以下结果

    使用 php 7.3.11

    使用 array_flip 一次和多次搜索,

    • 对于单个到几个搜索,in_array 和 array_search 更快。

    • 对于字符串搜索,翻转(一次)+ isset 在超过 200 次搜索时变得更快。

    • 对于数字搜索,翻转(一次)+ isset 在 10 次以上搜索时变得更快。

    字符串搜索结果(以秒为单位)

    N (array size) in_array flip isset array_search array_key_exists
    1,000,000 0.00845003 0.17343211 2.86E-6 0.00835395 5.01E-6
    100,000 0.00854707 0.12469196 7.15E-6 0.00861216 6.2E-6
    10,000 0.00854087 0.10549212 6.91E-6 0.00846505 4.05E-6

    数字搜索结果(以秒为单位),

    N (array size) in_array flip isset array_search array_key_exists
    1,000,000 0.01197696 0.06217289 6.2E-6 0.01673698 4.05E-6
    100,000 0.01191092 0.06582093 6.91E-6 0.01637983 4.05E-6
    10,000 0.01375008 0.07185006 5.01E-6 0.01485705 4.05E-6

    【讨论】:

    • 您的帖子看起来非常有用@Aurovrata,但目前很难阅读。你能不能用一个表格来格式化它,以一种更易读的方式显示基准?
    • 当然,我会努力找时间改进的
    • 这是一个 Markdown 表生成器 @Aurovrata: tablesgenerator.com/markdown_tables
    • 哇,这真的很方便。我将利用此表格格式更新我的答案
    • 有些东西看起来不对劲,in_array 的时间不会在 100 万到 10000 之间增加?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-24
    相关资源
    最近更新 更多