【问题标题】:Optimizing array merge operation优化数组合并操作
【发布时间】:2014-06-14 10:15:37
【问题描述】:

如果有任何帮助,我将不胜感激。

我有 7 个单独的数组,大约有 7 个数组。每个数组中有 90,000 个数字(我们称它们为数组 1-数组 7)。每个数组本身没有重复的数字。但是,数组之间可能存在重复。例如,array2 没有重复项,但可以与 arrays3 和 arrays4 有相同的数字。

问题: 我试图识别所有 7 个数组合并后重复 3 次的所有数字。

我必须做这个计算 1000 次,它需要 15 分钟,但这不行,因为我必须运行它 40 次 -- 代码:

如果您知道最适合此类计算的另一种语言,请告诉我。任何扩展建议,例如 redis 或 gearman 都有帮助。

for($kj=1; $kj<=1000; $kj++)
    {
$result=array_merge($files_array1,$files_array2,$files_array3,$files_array4,$files_array5,$files_array6,$files_array7);

$result=array_count_values($result);

$fp_lines = fopen("equalTo3.txt", "w");

foreach($result as $key => $val)
{
    if($result[$key]==3)
    {
    fwrite($fp_lines, $key."\r\n");
    }
}
fclose($fp_lines);
}

我也用字符串尝试了下面的代码,但是 array_map 调用和 array_count 值调用需要 17 分钟:

for($kj=1; $kj<=1000; $kj++)
    {

$result='';

for ($ii = 0; $ii< 7; $ii++) {
    $result .= $files_array[$hello_won[$ii]].'\r\n';
}

$result2=explode("\n",$result);//5mins
$result2=array_map("trim",$result2);//11mins
$result2=array_count_values($result2);//4-6mins

$fp_lines = fopen("equalTo3.txt", "w");

foreach($result2 as $key => $val)
{

    if($result2[$key]==3)
    {
    fwrite($fp_lines, $key."\r\n");
    }
}
fclose($fp_lines);

unset($result2);

【问题讨论】:

  • 您正在写入循环内的文件。这不是需要时间吗?您需要多久对这 90,000 个元素进行一次排序?如果它只是一次,也许不管它有多慢都做。如果需要定期完成,您需要一些方法来进行优化(也许通过在将每个元素添加到数据库时为每个元素维护一个计数器)。
  • 我和你的想法一样,是写调用很多,但是当我调查时,写时间是微不足道的。这个问题完全属于array_merge。 @this.lau_
  • 您能否让我们更深入地了解您的数据,以帮助我们找到最佳解决方案?例如(周日、周一、周二、周三、周四、周五、周六)有 7 个数组吗?数组中的数字有多大?例如34, 47, 21 或 337894294529243592, 38439434949238, 39859893922242 ?你猜这 7 个数组中有多少百分比是重复的?一式三份,等等?需要这样做 1000 次和 40 次是什么意思?
  • @scunliffe 当然!希望这个信息能让事情更清楚——这 7 个数组的数字长度在 10 到 5 个字符之间。这意味着一个数字可能看起来像这样 3456777890 或 34567。我猜一式三份的百分比约为 30%。 7 个数组组合永远不会相同,并且有 1000 个组合必须检查它们的一式三份。其他 40 次与解决方案无关,array_merge 需要 40 分钟,我的其余代码与 fwrite 调用相结合需要 1 分钟。 fwrite 是微不足道的,绝对不是问题。感谢您的帮助。

标签: php arrays performance optimization


【解决方案1】:

我建议更换

foreach($result as $key => $val)
{
    if($result[$key]==3)
    {
    fwrite($fp_lines, $key."\r\n");
    }
}

类似的东西

$res = array_keys(array_filter($result, function($val){return $val == 3;}));
fwrite($fp_lines, implode("\r\n", $res));

【讨论】:

    【解决方案2】:

    array_merge() 在数组中有更多元素时会明显变慢,因为(来自php.net):

    如果输入数组有相同的字符串键,那么后面的值 因为该键将覆盖前一个键。但是,如果数组 包含数字键,后面的值不会覆盖原来的 值,但会被附加。

    输入数组中带有数字键的值将重新编号为 在结果数组中从零开始递增键。

    所以这个函数实际上是在做一些条件语句。您可以将数组合并替换为正常添加,由循环(foreach 或任何其他)和[] 运算符组成。你可以写一个模仿array_merge的函数,比如(使用引用不复制数组..):

    function imitateMerge(&$array1, &$array2) {
        foreach($array2 as $i) {
            $array1[] = $i;
        }
    }
    

    你会看到速度的提升真的很难。

    【讨论】:

    • @ailvenge-这很有趣,我现在正在尝试实现它以查看它是如何工作的,但有些事情我不清楚该功能,我需要调用它 7 次$array1 将是最终的数组。为什么循环中没有 $array1[0.....90000] 之类的值? [] 保持为空吗?谢谢!!
    • @ailvenge-ok,我想我得到了它的一部分......你是说通过引用传递数组。
    • @ailvenge- 我想我得到了第二部分,$arr[] 这意味着 array_push。会试试这个。
    • [] 在数组末尾添加元素。我写的这个函数只合并了 2 个数组,所以如果你想合并 7 个数组,你可以用这个函数来合并 X 数组。引用也很重要,因为 PHP 中的函数通常会获取变量的副本,因此您将复制具有 90k 个数字的数组 X 次,这也会降低应用程序的速度,因此我们提供对它的引用以节省内存。跨度>
    • 记录:我对它进行了基准测试(PHP 8 x64),但速度并不快(大约慢了 x3 倍)。它还返回与 array_merge() 不同的值。
    【解决方案3】:

    这可能都是错误的,看看最后的编辑

    我也认为array_merge 是问题所在,但我的建议是实施 一个函数直接计算几个数组中的值,而不是先合并。 这在一定程度上取决于您的阵列中有多少重叠。如果重叠 非常小,那么这可能不会比合并快多少,但有显着 重叠(rand(0, 200000) 在我尝试时填充数组)这会快得多。

    function arrValues($arrs) {
        $values = array();
    
        foreach($arrs as $arr) {
            foreach($arr as $key => $val) {
                if(array_key_exists($key, $values)) {
                    $values[$val]++;
                } else {
                    $values[$val] = 1;
                }
            }
        }
        return $values;
    }
    
    var_dump(arrValues(array
        ($files_array1
        ,$files_array2
        ,$files_array3
        ,$files_array4
        ,$files_array5
        ,$files_array6
        ,$files_array7
        )));
    

    在我的机器上计算大约需要 0.5 秒,然后再打印 2 秒。

    -编辑-

    我也不清楚为什么你做同样的事情 1000 次?数组是否不同 每次还是什么?说一下原因可能会给人们更多的想法……

    -再次编辑-

    经过更多探索,我认为 array_merge 不再有错。你不 有足够的重叠可以从直接计算所有内容中受益匪浅。你 调查您机器上的可用内存?对我来说,将 7 个数组与 90k 个元素合并 每个需要〜250M。如果您允许 php 使用这么多内存,我假设您 有,因为你没有得到任何分配错误,那么问题可能是内存 根本不可用,并且您会遇到很多页面错误?如果这不是问题,那么 在什么样的机器上,你使用的是什么 php 版本?我测试了你的 5.5 和 5.4 上的原始代码并修复内存问题,它也可以在大约 0.5 秒内运行。那 每次迭代都会提醒你。现在,如果您在同一个 php 脚本中执行此操作 1000 次,那么 这需要一段时间。考虑到您每次都分配所有这些内存,更是如此。

    我认为您确实应该考虑将内容放入数据库中。鉴于您的数字,您似乎总共有约 5 亿行。这在 php 中处理起来非常麻烦。数据库使事情变得简单。

    【讨论】:

    • 是的!我必须做 1000 次,因为每次的数组都不一样。这七个文件永远不会相同。 @monocell
    • 因此您有 7000 个文件,每个文件有 90k 行,并且您希望在 10 个文件的组中查找出现超过 3 次的值。这听起来像一个数据库可能正是你想要的。他们真的很擅长这些东西......
    • 非常感谢您对此的帮助,我希望我能接受两个答案!!!我会采纳您的建议并尝试将其放入数据库中。非常感激。 @monocell
    猜你喜欢
    • 1970-01-01
    • 2011-02-28
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    • 2016-02-18
    • 2012-10-25
    • 2020-07-21
    • 1970-01-01
    相关资源
    最近更新 更多