【问题标题】:I have two unordered integer arrays, and i need to know how many integers these arrays have in common我有两个无序整数数组,我需要知道这些数组共有多少个整数
【发布时间】:2009-07-03 12:32:49
【问题描述】:

我在 LAMP 环境中工作,所以 PHP 是语言;至少我可以用python。

正如标题所说,我有两个无序整数数组。

$array_A = array(13, 4, 59, 38, 9, 69, 72, 93, 1, 3, 5)

$array_B = array(29, 72, 21, 3, 6)

我想知道这些数组共有多少个整数;在示例中,如您所见,结果是 2。我对整数的共同点不感兴趣,例如 (72, 3)。

我需要一种比获取数组 B 的每个元素并检查它是否在数组 A 中更快的方法 ( O(nxm) )

数组可以通过 asort 或 sql 排序(它们来自 sql 结果)进行排序。

我想到的一个想法是为每个数组创建一个“向量”,其中整数是一个位置,其值为 1,不存在的整数为 0。

所以,对于数组 A(从位置 1 开始)

(1, 0, 1, 1, 1, 0, 0, 0, 1, 0, ...)

数组 B 也一样

(0, 0, 1, 0, 0, 1, ...)

然后用一个循环比较这两个向量。问题是这样的向量长度大约是400k。

【问题讨论】:

  • 如果两个列表都来自同一个数据库并且字段都被索引,为什么不使用(完全外部)JOIN?

标签: php arrays sorting


【解决方案1】:

根据您的数据(大小),您可能希望使用array_intersect_key() 而不是array_intersect()。显然,array_intersect 的实现(测试 php 5.3)不使用任何优化/缓存/任何东西,而是循环遍历数组并为数组 A 中的每个元素一一比较值。哈希表查找比这快得令人难以置信。

<?php
function timefn($fn) {
    static $timer = array();
    if ( is_null($fn) ) {
        return $timer;
    }
    $x = range(1, 120000);
    $y = range(2, 100000);
    foreach($y as $k=>$v) { if (0===$k%3) unset($y[$k]); }

    $s = microtime(true);
    $fn($x, $y);
    $e = microtime(true);

    @$timer[ $fn ] += $e - $s; 
}

function fnIntersect($x, $y) {
    $z = count(array_intersect($x,$y));
}

function fnFlip($x, $y) {
    $x = array_flip($x);
    $y = array_flip($y);
    $z = count(array_intersect_key($x, $y));
}


for ($i=0; $i<3; $i++) {
    timefn( 'fnIntersect' );
    timefn( 'fnFlip' );
}

print_r(timefn(null));

打印

数组
(
    [fnIntersect] => 11.271192073822
    [fnFlip] => 0.54442691802979
)
这意味着 array_flip/intersect_key 方法在我的笔记本上要快约 20 倍。 (像往常一样:这是一个临时测试。如果您发现错误,请告诉我......我期待着 ;-))

【讨论】:

  • 很有趣,但是两个数组之一的元素从 70k 到 30k 不等,所以我认为数组翻转是瓶颈;我在你的建议之外测试了这个,但它变得有点慢:(
  • 奇怪,因为我的测试对两个数组都使用了 ~100k 元素。它具有更高的内存峰值,因此如果您的服务器的内存/堆处于压力之下,这可能会成为一个问题。我会修改测试...
  • 我的意思是它比sql查询慢,而不是array_intersect的应用。很抱歉错过了这些信息
  • 啊,我明白了 ;-) 唷......我尝试了大约 30 分钟来提出一个“勾选”array_flip 方法的测试用例。是的,如果任何涉及将所有记录从数据库服务器传输到PHP进程的内存然后比较它们的方法比在数据库“内”执行它更快,我会感到惊讶。跨度>
【解决方案2】:

我对 PHP 了解不多,因此您可能会从其他人那里得到更具体的答案,但我想介绍一种与语言无关的方法。

通过检查 A 中的每个元素与 B 中的每个元素,确实是 O(n2) [我假设这里的数组长度相同,以简化方程式,但推理相同将适用于不同长度的数组]。

如果要对两个数组中的数据进行排序,则可以将时间复杂度降低到 O(n log n) 或类似,具体取决于所选算法。

但您需要记住,复杂性只有对更大的数据集才真正变得重要。如果您给出的这两个数组是典型的大小,我会说不要对其进行排序,只需使用“将所有内容与所有内容进行比较”方法 - 排序不会给您带来足够的优势。 50 个元素的数组仍然只会给你 2,500 次迭代(我不知道这对 PHP 是否可以接受,对于 C 和其他编译语言来说,这肯定是鸭子背上的水)。

在有人介入并声明您应该计划更大的数据集以防万一之前,这就是 YAGNI,与过早优化一样不必要。您可能永远需要它,在这种情况下,您已经浪费了本可以花在其他地方更好的时间。当它成为一个问题时才实施它(当然这是我的观点,其他人可能不同意)。

如果数据集真的大到足以使 O(n2) 不可行,我认为排序然后并行遍历数组可能是你最好的选择。

另一种可能性是,如果数字范围不太大 - 那么您提出的布尔向量解决方案是非常可行的,因为这将是 O(n),遍历两个数组以填充向量,然后比较固定的两个向量中的位置。但我假设您的范围太大,或者您不会已经提到 400K 的要求。但同样,数据集的大小将决定是否值得这样做。

【讨论】:

    【解决方案3】:

    最简单的方法是:

    count(array_intersect($array_A, $array_B));
    

    如果我明白你在追求什么。 应该很快。

    【讨论】:

    • 应该很快,但...不是 ;-)
    • 这就是答案;无论如何,我的问题仍然比 SQL 慢;我会向我保证,不存在更好的方法。
    • 你是说这个方案比你的SQL方案慢?
    【解决方案4】:

    如果两个数组都来自 SQL,你能不能编写一个 SQL 查询,对这两组数据进行内连接来得到你的结果?

    【讨论】:

    • 我已经在 sql 中有这个了,而且太慢了 :|所以我想检查是否有可能加快速度。事实是 sql 通过一个 220 万条记录的表,这会减慢很多
    • 这听起来像是没有正确使用索引。如果有好的索引并且使用得当,MySQL 应该能够很快做到这一点。
    • 是的,听起来像,但这是一个包含两个整数字段的表。主键是两者的组合,每个字段都有一个btree索引;我认为没有其他可能性。我不想详细输入,但这是我必须做很多很多次的操作;反正是一批。
    • 对于它的价值,我建议您尝试将问题重新提出为 SQL 问题(描述您在该级别所做的事情),看看是否有更好的方法来处理它水平。
    【解决方案5】:

    您需要array_intersect() 函数。从那里你可以计算结果。在你知道你有问题之前不要担心速度。内置函数的执行速度比您用 PHP 编写的任何东西都要快。

    【讨论】:

      【解决方案6】:

      我编写了一个 PHP 扩展,它为高效的集合操作提供函数,例如联合、交集、二分搜索等。内部数据布局是一个普通的 int32_t 数组,存储在 PHP 字符串中。操作基于合并算法。

      例子:

          // Create two intarrays
          $a = intarray_create_from_array(array(1, 2, 3));
          $b = intarray_create_from_array(array(3, 4, 5));
          // Get a union of them
          $u = intarray_union($a, $b);
          // Dump to screen
          intarray_dump($u);
      

      可在此处获取:https://github.com/tuner/intarray

      【讨论】:

        猜你喜欢
        • 2011-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多