从一维数组创建关联数组

时间:2019-05-14 18:59:55

标签: php arrays

不确定是什么标题...

.csv示例

tennis,soccer,sports
car,plane,things
jeans,shirt,things

我的最终理想目标 应该是一个如下数组:

Array
(
    [sports] => Array
        (
            [0] => tennis
            [1] => soccer
        )

    [things] => Array
        (
            [0] => car
            [1] => plane
            [2] => jeans
            [3] => shirt
        )

)

这是我最近达到上述目标的尝试(经过多次尝试):

<?php
$f_name = 'test.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);

$tmp = array();
$data_for_email = array();

for ($i = 0; $i < $c; $i++) {
    // Remove last element and make it a key
    $le = array_pop($csv_data[$i]);
    $tmp[$le] = $csv_data[$i];
    $data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}

print_r($data_for_email);
?>

这就是我得到的结果:

Array
(
    [sports] => Array
        (
            [0] => tennis
            [1] => soccer
            [2] => tennis
            [3] => soccer
            [4] => tennis
            [5] => soccer
        )

    [things] => Array
        (
            [0] => car
            [1] => plane
            [2] => jeans
            [3] => shirt
        )

)

如您所见,我在[sports]数组中得到了.csv第1行的副本。

我的要求的详细说明:

  1. 每行有3个字段。
  2. 第三个字段在新的关联数组中成为key
  3. values的其余两个字段(第1个和第2个)变为key
  4. 由于多行可能(并且确实)包含相同的第三字段(而第一字段和第二字段的组合始终不同),因此我需要将所有这些重复键的值合并为1。

P.S。之后,我可以解析该数组(以删除重复的值),但是真正的.csv文件很大,处理它变得太慢,并且在用// MEMORY ERROR标记的行上收到以下错误:< / p>

  

致命错误:允许的内存大小为134217728字节已耗尽

我尝试增加内存限制,但我希望尽可能避免这种情况。

5 个答案:

答案 0 :(得分:1)

应该容易一些。不需要array_merge_recursive

foreach($csv_data as $row) {
    $key = array_pop($row);
    if(!isset($data_for_email[$key])) {
        $data_for_email[$key] = [];
    }
    $data_for_email[$key] = array_merge($data_for_email[$key], $row);
}

答案 1 :(得分:0)

更高的内存效率将是:

  1. 不读取内存中的整个文件。 fgetcsv一次读取一行
  2. 避免递归合并

代码:

$handle = fopen($f_name, 'r');
if (!$handle) { 
    // Your error-handling
    die("Couldn't open file");
}

$data_for_email = array();
while($csvLine = fgetcsv($handle)) {
    // Remove last element and make it a key
    $le = array_pop($csvLine);
    if (isset($data_for_email[$le])) {
        $data_for_email[$le] = array_merge($data_for_email[$le], $csvLine);
    } else {
        $data_for_email[$le] = $csvLine;
    }
}

fclose($handle);

答案 2 :(得分:0)

您只需要在每个循环中初始化$tmp,即可解决您的问题。检查以下代码:

for ($i = 0; $i < $c; $i++) {
    // Remove last element and make it a key
    $le = array_pop($csv_data[$i]);
    $tmp = []; //Reset here
    $tmp[$le] = $csv_data[$i];
    $data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}

希望它对您有帮助。

答案 3 :(得分:0)

使用密钥名称来获得唯一列表。如果有大量数据,它比合并便宜。

RaycastHit hit;
  hit.point;

输出:

$handle = fopen('test.csv', 'r');
$res = [];

while ($data = fgetcsv($handle)) {
    list($first, $second, $type) = $data;
    $res[$type] = ($res[$type] ?? []);

    array_map(function($e)use(&$res, $type) {
        $res[$type][$e] = $e;
    }, [$first, $second]);
}

答案 4 :(得分:0)

我也做了点什么,但是现在其他的都快了。 :D 我已经做到了,它并没有完全满足您的要求,但是也许可以进一步帮助您。

不幸的是,我现在还没有进一步想告诉你:)

这是您的index.php(或任何称为文件的文件。)

<?php
include "Data.php";

$f_name = 'in.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);

$tmp = array();
$data_for_email = array();

foreach ($csv_data as $data){
    $key = array_pop($data);
    array_push($data_for_email,new Data($data,$key));
}
foreach ($data_for_email as $data){
    array_push($tmp,$data->getValue());
}

foreach ($tmp as $value){
    print_r($value);
    echo "<br>";
}

,这里是数据类:

<?php


class Data
{
    private $value = [];

    public function __construct($data, $key)
    {
        $this->value[$key]=$data;
    }

    /**
     * @return array
     */
    public function getValue()
    {
        return $this->value;
    }
}

作为输出,您将像这样:

Array ( [sports] => Array ( [0] => tennis [1] => soccer ) ) 
Array ( [things] => Array ( [0] => car [1] => plane ) ) 
Array ( [things] => Array ( [0] => jeans [1] => shirt ) ) 

ps: 当然还有另一个功能可以总结相同的键,但是不知何故我现在什么都找不到... 希望对您有所帮助:)