【问题标题】:Improve speed cross-mapping array of arrays提高数组的交叉映射数组的速度
【发布时间】:2016-05-18 07:05:12
【问题描述】:

只是在从 Perl 到 PHP 的转换中寻求一点帮助。我利用散列将值映射为从两个文件读取的两个数组的键。我使用的文件不是很大,一个大约 150,000 行,另一个大约 50,000 行。在 Perl 中,这大约需要 10 秒,但在 PHP 中,我将读入的文件从 150,000 行减少到大约 20,000 行,这需要将近 3 分钟。我想知道这是语言的限制还是我的设计本身就有缺陷。

现有的两个数组数组是$ao_hash和$string_hash,构建如下:

// Load file contents
$file_contents = str_replace("\t","|",file_get_contents($_FILES['file']['tmp_name']));
$file_array = explode("\n",$file_contents);

// Pass client dictionary into an array of arrays
foreach ($file_array as $line) {
    $line_array = explode("|",$line);
    if (stripos($line_array[0], 'mnemonic') !== false) { 
        continue; 
    }

    if (!isset($line_array[1])) {
        continue;
    }

    if (stripos($line_array[1], 'n') !== false) {
        continue;
    }

    if (!isset($line_array[10])) {
        continue;
    }

    $ao_hash[$line_array[10]] = $line;
}

两个哈希都是使用这种方法构建的,并且都运行良好(预期结果,快速执行)。内容如下:

$array1[NDC] = some|delimited|file|output
$array2[NDC] = another|file|with|delimited|output

我使用 NDC 作为主键来交叉映射两个数组。

// Compare the client's drug report against the cut-down file
while (list ($key, $value) = each ($ao_hash)) {

    // Use the NDC to match across array of arrays
    if (isset($string_hash[substr($key,0,11)])) {
        $string_selector = $string_hash[substr($key,0,11)];
    }

    // Check if the client NDC entry exists in cut-down file
    if (!isset($string_selector)) {

        // No direct NDC match, reserve for an FSV look-up
        $ao_array = explode("|", $value);
        if (isset($ao_array[2]) && isset($ao_array[16])) {
            $no_matches[$ao_array[2].'|'.$ao_array[16]]['NDC'] = $ao_array[10];
            $no_matches[$ao_array[2].'|'.$ao_array[16]]['MNEMONIC'] = $ao_array[0];
        }
    } else {

        // Direct match found
        $ao_array = explode("|", $value);
        $cutdown_array = explode("|", $value);
        foreach ($cutdown_array as $cutdown_col) {
            if ($cutdown_col == "") {
                $cutdown_col = "0";
            }
            $cutdown_verified[] = $cutdown_col;
        }

        // Drop the last column
        array_pop($cutdown_verified);

        // Merge into a single string
        $final_string = implode("|", $cutdown_verified);

        // Prepare data for FSV match
        if (isset($ao_array[2]) && isset($ao_array[16])) {
            $yes_matches[$ao_array[2].'|'.$ao_array[16]]['DRUG_STRING'] = $final_string;
        }

        // Add the mnemonic to the end
        $final_string .= '|'.$ao_array[0];
        $drug_map[$ao_array[0]] = $final_string;
    }
}

任何帮助都会很棒,希望它运行得更快。

【问题讨论】:

  • 我没有做过任何测试,但是有几件事对我来说是微优化和我有的一般问题。上传的文件似乎是 CSV 或制表符分隔列表。您是否尝试过使用fgetcsvstr_getcsv?接下来,您只匹配密钥中的前 10 个字符。而不是存储整个密钥,只存储前 10 个字符,这将节省 2 个 substr(不多)。与其将字符串存储在映射中,不如存储数组。这将减少爆炸电话。
  • 这是一个管道分隔的文本文件,但我想捕获制表符分隔的文件(从 Excel 导出的用户并不总是知道切换到管道)。我不能 substr 来存储密钥,因为 NDC 可能有第 12 个值(如 A 或 B),我需要稍后区分它。我去看看能不能减少微编辑。我会看看我是否可以减少爆炸电话。在 Perl 中,split/join 调用很容易被滥用,因为它们相对较快。

标签: php arrays dictionary hash


【解决方案1】:

Redditor https://www.reddit.com/user/the_alias_of_andrea 解决了这个问题:

而不是使用:

while (list($key, $value) = each($ao_hash))

使用起来会更有效率

foreach ($ao_hash as $key => $value)

现在立即执行一个 13MB 的文件,我得到了预期的结果。

【讨论】:

    猜你喜欢
    • 2019-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-31
    相关资源
    最近更新 更多