【问题标题】:CSV to Associative ArrayCSV 到关联数组
【发布时间】:2011-06-15 16:07:52
【问题描述】:

我看过很多关于如何获取 CSV 文件然后创建以标题为键的关联数组的示例。

例如:

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

它将创建一个数组,例如Array[$num][$key],其中$key 将是品牌、型号、零件、测试。

所以如果我想访问测试值“434”,我将不得不循环数组中的每个索引,然后忽略任何不是本田的品牌,以及任何不是思域的模型


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

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

或通过循环遍历本田拥有的每个模型来控制 for 语句......类似于

foreach $model in Array['Honda']

至少我需要能够浏览给定已知品牌的每个模型并访问每个模型的所有相关信息。

编辑:

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

brand model part price shipping description footnote

其中我需要访问与零件相关的所有信息(价格、运输、描述、脚注)

【问题讨论】:

标签: php arrays csv associative


【解决方案1】:

冗长的解决方案太多。我一直觉得这是最简单的:

<?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);
    }
?>

【讨论】:

  • 很棒的代码,它非常适合逗号分隔的 csv。但是,如果它是分号分隔的 csv 怎么办?我找不到用分号分隔的 csv 做同样的方法。
  • @Alex,除了争论 CSV 的首字母缩写词 Comma Separated Values 的语义外,您还可以设置 str_getcsv 函数的分隔符。我希望这会有所帮助!
  • 如果您想将参数(如分隔符)传递给 str_getcsv,请使用:$rows = array_map(function($row) { return str_getcsv($row, ';'); }, file('file.csv'));
  • @marcovtwout,请记住,您可以将附加参数作为array_map() 的第三个参数传递。
  • 这个解决方案可能非常消耗内存,因为它创建了一个包含整个 CSV 文件的数组,而不是将单行读入内存
【解决方案2】:

逐行遍历 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);
}

【讨论】:

  • 如果你要改变 $array[$i][$k] = $value;到 $array[$i][$fields[$k]] = $value;你会得到标题作为键。
  • 在看到他的评论之前,我正要和@CraigHooghiem 说同样的话。使用$fields[$k],上述答案按预期工作。
  • 如果标题行值周围的空格是一个问题,您可以使用$fields = array_map('trim', $row); 清理
【解决方案3】:

要创建关联列表数组,请使用以下内容:

$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=&gt;Honda, Model=&gt;Civic, Part=&gt;135) 调用它以过滤掉搜索到的模型。其他位置数组结构似乎不太可行,除非您只想访问“Test”属性。

【讨论】:

    【解决方案4】:

    试试这个简单的算法:

            $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);
    

    【讨论】:

    • 这个答案缺少教育解释。
    【解决方案5】:

    使用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/en/function.fgetcsv.php

    【讨论】:

    • 提示:如果您在此处使用零 (0) 而不是 1000:fgetcsv($handle, 0, ","),则每行没有字符限制。如果您不确定每行可能包含多少个字符,则非常适合。
    【解决方案6】:

    这是一个可以通过指定本地文件或 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);
    

    【讨论】:

      【解决方案7】:

      这是我的解决方案,与其他人所说的类似,但使用 fgetcsv 的 while 循环,并使用计数器和 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);
      

      【讨论】:

        猜你喜欢
        • 2012-12-22
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多