CSV转换为关联数组

62

我看过很多关于如何将CSV文件转换为以头部为键的关联数组的示例。

例如:

Brand,Model,Part,Test
Honda,Civic,123,244
Honda,Civic,135,434
Toyota,Supra,511,664

这会创建一个数组,例如Array[$num][$key],其中$key是Brand,Model,Part,Test等。所以如果我想要访问测试值"434",我必须循环遍历数组中的每个索引,然后忽略任何不是本田品牌的商品和不是思域型号的车型。


我需要做的是最直接地访问该值,而不是通过循环遍历每个$num索引。我希望能够使用以下方式访问测试值"434":

Array['Honda']['Civic']['135']

或者通过循环遍历Honda拥有的每个车型来控制for语句,例如:

foreach $model in Array['Honda']

至少我需要能够在已知品牌的情况下遍历每个车型并访问每个车型的所有相关信息。

编辑:

只是为了确认我正在设置一个示例。我的实际数据具有类似以下的标题:

brand model part price shipping description footnote

其中我需要访问与零件(price、shipping、desc、footnote)相关的所有信息。


7个回答

143

解决方案太过复杂了。我一直认为这个是最简单的:

<?php
    /* Map Rows and Loop Through Them */
    $rows   = array_map('str_getcsv', file('file.csv'));
    $header = array_shift($rows);
    $csv    = array();
    foreach($rows as $row) {
        $csv[] = array_combine($header, $row);
    }
?>

4
神奇的代码,它在逗号分隔的 CSV 文件中运行得很好。但是如果是分号分隔的 CSV 文件呢?我找不到用分号分隔的 CSV 文件实现相同功能的方法。 - Alex
4
除了争论CSV缩写代表“逗号分隔值”这个术语外,你还可以设置str_getcsv函数的分隔符。希望这能帮到你! - Daerik
10
如果您想向str_getcsv传递参数(例如分隔符),请使用以下代码:$rows = array_map(function($row) { return str_getcsv($row, ';'); }, file('file.csv'));该代码会从"file.csv"文件中读取数据,每行数据都会被str_getcsv()函数处理并存储在数组$rows中。在调用str_getcsv()时,第二个参数";"表示分隔符为分号。 - marcovtwout
2
@marcovtwout,请记住,您可以将其他参数作为array_map()的第三个参数传递。 - Daerik
6
这个解决方案可能非常占用内存,因为它创建了一个包含整个CSV文件的数组,而不是将单行读入内存。 - AngryUbuntuNerd
显示剩余6条评论

73

逐行遍历CSV文件,并像这样插入到数组中:

$array = $fields = array(); $i = 0;
$handle = @fopen("file.csv", "r");
if ($handle) {
    while (($row = fgetcsv($handle, 4096)) !== false) {
        if (empty($fields)) {
            $fields = $row;
            continue;
        }
        foreach ($row as $k=>$value) {
            $array[$i][$fields[$k]] = $value;
        }
        $i++;
    }
    if (!feof($handle)) {
        echo "Error: unexpected fgets() fail\n";
    }
    fclose($handle);
}

16
如果您将 $array[$i][$k] = $value; 更改为 $array[$i][$fields[$k]] = $value;,则会将标题作为键。 - Craig Hooghiem
2
在看到@CraigHooghiem的评论之前,我正要说和他一样的话。使用$fields[$k],上面的答案可以按预期工作。 - DWils
如果标题行周围的空格是一个问题,您可以使用 $fields = array_map('trim', $row); 进行清理。 - jerrygarciuh

22

要创建一个关联列表数组,可以使用以下代码:

$keys = fgetcsv($f);
while (!feof($f)) {
    $array[] = array_combine($keys, fgetcsv($f));
}

为了遍历并过滤特定属性,请编写以下函数:

function find($find) {
    foreach ($array as $row) {
         if (array_intersect_assoc($row, $find) == $find) {
             $result[] = $row;
         }
    }
}

如果你想用$find = array(Brand=>Honda, Model=>Civic, Part=>135)来过滤搜索的型号,那么你可以调用它。另一种定位数组结构似乎不太可行,除非你只想访问“Test”属性。


5

尝试使用这个简单的算法:

        $assocData = array();

        if( ($handle = fopen( $importedCSVFile, "r")) !== FALSE) {
            $rowCounter = 0;
            while (($rowData = fgetcsv($handle, 0, ",")) !== FALSE) {
                if( 0 === $rowCounter) {
                    $headerRecord = $rowData;
                } else {
                    foreach( $rowData as $key => $value) {
                        $assocData[ $rowCounter - 1][ $headerRecord[ $key] ] = $value;  
                    }
                }
                $rowCounter++;
            }
            fclose($handle);
        }

        var_dump( $assocData);

1
这个答案缺少教育性的解释。 - mickmackusa

3

使用 fgetcsv() 似乎是完成该任务最直接和合理的工具。

csv.csv 内容:

Brand,Model,Part,Test
Honda,Civic,123,244
Honda,Civic,135,434
Toyota,Supra,511,664

代码:

$assoc_array = [];
if (($handle = fopen("csv.csv", "r")) !== false) {                 // open for reading
    if (($data = fgetcsv($handle, 1000, ",")) !== false) {         // extract header data
        $keys = $data;                                             // save as keys
    }
    while (($data = fgetcsv($handle, 1000, ",")) !== false) {      // loop remaining rows of data
        $assoc_array[] = array_combine($keys, $data);              // push associative subarrays
    }
    fclose($handle);                                               // close when done
}
echo "<pre>";
    var_export($assoc_array);                                      // print to screen
echo "</pre>";

输出:

array (
  0 => 
  array (
    'Brand' => 'Honda',
    'Model' => 'Civic',
    'Part' => '123',
    'Test' => '244',
  ),
  1 => 
  array (
    'Brand' => 'Honda',
    'Model' => 'Civic',
    'Part' => '135',
    'Test' => '434',
  ),
  2 => 
  array (
    'Brand' => 'Toyota',
    'Model' => 'Supra',
    'Part' => '511',
    'Test' => '664',
  ),
)

资源:http://php.net/manual/zh/function.fgetcsv.php

该函数用于从文件中读取CSV格式的数据。CSV是一种常用的电子表格文件格式,它使用逗号作为字段之间的分隔符。


提示:如果您在此处使用零(0)而不是1000:fgetcsv($handle, 0, ","),则每行没有字符限制。 如果您不确定每行可能有多少个字符,则可以使用此选项。 - Richard

2

以下是一种解决方案,可以通过指定本地文件或URL来实现。您还可以切换关联开关。希望这有所帮助。

class CSVData{
    public $file;
    public $data;
    public $fp;
    public $caption=true;
    public function CSVData($file=''){
        if ($file!='') getData($file);
    }
    function getData($file){
        if (strpos($file, 'tp://')!==false){
            copy ($file, '/tmp/csvdata.csv');
            if ($this->fp=fopen('/tmp/csvdata.csv', 'r')!==FALSE){
                $this->readCSV();
                unlink('tmp/csvdata.csv');
            }
        } else {
            $this->fp=fopen($file, 'r');
            $this->readCSV();
        }
        fclose($this->fp);
    }
    private function readCSV(){
        if ($this->caption==true){
            if (($captions=fgetcsv($this->fp, 1000, ","))==false) return false;
        }
        $row=0;
        while (($data = fgetcsv($this->fp, 1000, ",")) !== FALSE) {
            for ($c=0; $c < count($data); $c++) {
                $this->data[$row][$c]=$data[$c];
                if ($this->caption==true){
                    $this->data[$row][$captions[$c]]=$data[$c];
                }
            }
            $row++;
        }
    }
}

请尝试以下用法:

$o=new CSVData();
$o->getData('/home/site/datafile.csv');
$data=$o->data;
print_r($data);

1

这是我的解决方案,与其他类似,但使用了while循环和fgetcsv,并使用计数器和array_combine将第一行设置为键。

    $rownum = 0;
    while (($row = fgetcsv($openedFile, 1000, ',')) !== FALSE) {
        if ($rownum > 0) {
            $row = array_combine($importarray[0], $row);
        }
        array_push($importarray, $row);
        $rownum++;
    }
    array_shift($importarray);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接