CSV 到关联数组
Posted
技术标签:
【中文标题】CSV 到关联数组【英文标题】:CSV to Associative Array 【发布时间】: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
其中我需要访问与零件相关的所有信息(价格、运输、描述、脚注)
【问题讨论】:
Example(s) how to do that withSplFileInfo
【参考方案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=>Honda, Model=>Civic, Part=>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);
【讨论】:
以上是关于CSV 到关联数组的主要内容,如果未能解决你的问题,请参考以下文章