【问题标题】:Best practice looping through huge arrays循环遍历巨大数组的最佳实践
【发布时间】:2014-05-29 12:45:40
【问题描述】:

我有两个巨大的数组:

  • 数组 A 有 4900 个项目(每个项目都是一个小数组)
  • 数组 B 有 700 个项目(每个项目也是一个小数组)

所以基本上这些就是我的数组:

A = array (
    [0] => array(
        "name" => "KE-KE IMPEX ",
        "email" => "someemai@gmail.com",
        "kezbCompany" => "Fragrance",
        "startDate" => "2013-03-25 00:00:00",
        "endDate" => "2014-03-25 00:00:00",
        "companyBase" => "06 20 232 2534"
    )
    ...
    [4900] => array(
        "name" => "Jane Doe",
        "email" => "zzer@sad.com",
        "kezbCompany" => "sadsad",
        "startDate" => "2013-03-25 00:00:00",
        "endDate" => "2014-03-25 00:00:00",
        "companyBase" => "06 20 232 2534"
    )
)

B = array (
    [0] => array(
        "name" => "KE-KE IMPEX 46554 sda",
        "email" => "xxx@gmail.com",
        "kezbCompany" => "546wer",
        "startDate" => "2013-03-25 00:00:00",
        "endDate" => "2014-03-25 00:00:00",
        "companyBase" => "06 20 232 2534"
    )
    ...
    [700] => array(
        "name" => "45 Jane Doe",
        "email" => "kekeimpex@gmail.com",
        "kezbCompany" => "asd",
        "startDate" => "2013-03-25 00:00:00"        
    )
)

例如,小物品看起来像这样(A和B的展位):

array(
  'name' => 'John Doe',
  'email' => 'john@doe.com'
)

所以我需要做的是:检查哪个小数组同名。

但请记住,大多数时候这两个小数组的结构不会相同。

因此,例如,他们的电子邮件可能不同。现在,如果我先遍历 A,然后再循环遍历 B,则需要很长时间。

这是我当前的代码:

$szData = file_get_contents('szData.txt');
$kData = file_get_contents('kData.txt');

$A = json_decode($szData);
$B = json_decode($kData);

$foundNr = 0;

foreach ($A as $key => $sz)
{
    $cName = $sz->companyName;

    foreach ($B as $index => $k)
    {
        $pattern = '/^(.*)+('.$cName.')/i';

        echo "SzSor: " . $key . " --- Ksor: " . $index . "</br>";

        if (preg_match($pattern, $k->companyName))
        {
            $founData[] = $k->companyName;

            ++$foundNr;
        }
    }
}

有什么想法吗?

【问题讨论】:

  • 首先发布您当前的代码。
  • 看看这里:phpdreams.com/blog-posts/best-practice-array-loops.html。这个人对遍历数组的不同方式和处理大型数组的最佳实践(在撰写本文时)进行了基准测试。希望这会有所帮助!
  • 这是我们使用数据库管理系统的原因之一的一个很好的例子。
  • @DerikNel 这个链接是个糟糕的建议,他们已经触发 PHP 制作了一百万个数组副本,然后抱怨它很慢(您还会注意到它也会消耗大量内存,因为它同时持有所有这些数组,直到它可以在最后取消引用它们)。 PHP 有一个引用特性,用于在迭代数组时更新数组以避免这种情况。 foreach($array AS &amp;$key){ $key++; },在我的测试中,这比他建议的任何替代方法快了近 20%。请参阅this answer 了解更多信息。
  • @scragar 同意,该链接主要是为了演示遍历数组的不同方法之间的速度差异。

标签: php loops foreach


【解决方案1】:

一种解决方案是首先将子数组中的所有数据合并为一个内爆字符串(John Doe-john@doe.com),然后使用快速函数来比较匹配的字符串:

$szData = file_get_contents('szData.txt');
$kData = file_get_contents('kData.txt');

$A = json_decode($szData);
$B = json_decode($kData);

$foundNr = 0;

$B_sample = array();
foreach  ($B as $index => $data){
    $B_sample[$index] = implode('-',$data);
    //or use some other custom procedure to create unique string from the data.
}


$B_sample = array();
foreach  ($A as $index => $data){
    $A_sample[$index] = implode('-',$data);
}

$A_B_intersect = array_intersect ($A_sample , $B_sample ); // the KEYS in the result array are from $A

$foundNr = count($A_B_intersect);

foreach($A_B_intersect as $key->$data){
    $founData[] = $A[$key]->companyName;
}

如果您可以在构建 $A 的同时创建 $A_sample,重复使用相同的循环,这将带来额外的好处。

【讨论】:

    【解决方案2】:

    您可能最好避免在此处使用自己的循环等,并尝试使用内置的 PHP 函数,例如:

    in_array:

    代码取自文档:

    <?php
    $os = array("Mac", "NT", "Irix", "Linux");
    if (in_array("Irix", $os)) {
        echo "Got Irix";
    }
    if (in_array("mac", $os)) {
        echo "Got mac";
    }
    ?>
    
    The second condition fails because in_array() is case-sensitive, so the program above will display:
    
    Got Irix
    
    Example #2 in_array() with strict example
    <?php
    $a = array('1.10', 12.4, 1.13);
    
    if (in_array('12.4', $a, true)) {
        echo "'12.4' found with strict check\n";
    }
    
    if (in_array(1.13, $a, true)) {
        echo "1.13 found with strict check\n";
    }
    ?>
    
    The above example will output:
    
    1.13 found with strict check
    

    因此,虽然您可能仍需要遍历一个数组来比较所有可能的值,但最有效的代码通常来自使用内置函数。

    说了这么多,写几个简单的循环并测试它,看看什么性能最好。如果您知道数据的结构,则可以完全跳过许多元素 - 例如,如果您知道数据将以字母顺序出现,并且您正在寻找以“S”开头的内容,请执行一次跳过 100 条记录的循环,直到达到“S”值 - 然后返回到它之前的最后一个条目。像这样的东西。这种想法有助于快速高效地编写代码 - 如果您可以跳过 5000 个元素中的前 3500 个元素中的 100 个元素中的 99 个,则不要逐个元素地执行搜索。

    【讨论】:

    • @Mr.Sam 嗨,我是strtolower,它想成为朋友:)
    • 如果目标是编写高效的代码,那么使用内置数组函数通常比 foreach 循环慢。开始优化所示代码性能的地方是摆脱正则表达式。此外,您的逻辑与上面发布的不同。
    • 对不起,但我认为这对我不利,我要编辑我的问题,因为我只是发现它不太清楚
    • @Fluffeh 大多数时候这两个小数组的结构不会相同。所以我不认为我可以使用 in_array(),因为我会得到很小比例的“相同数组”。这就是我使用正则表达式的原因。
    猜你喜欢
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-07
    相关资源
    最近更新 更多