Процесс CSV в массив с заголовками столбцов для ключа
У меня есть CSV с первой строкой, содержащей имена полей. Пример данных...
"Make","Model","Note"
"Chevy","1500","loaded"
"Chevy","2500",""
"Chevy","","loaded"
Мне нужно, чтобы мои данные были отформатированы в виде массива пар ключ-значение, где имя ключа является заголовком столбца. Я думаю, что это будет что-то вроде этого для строки 1:
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => "loaded"
];
... строка 2...
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => ""
];
... и строка 3...
$array = [
"Make" => "Chevy",
"Model" => "",
"Note" => "loaded"
];
Я не уверен, как это сделать, кроме как статически - проблема в том, что столбцы с соответствующими данными могут меняться от одного файла к следующему... столбцы переставляются, удаляются или добавляются.
Ваши идеи очень ценятся.
8 ответов
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
print_r($all_rows);
PHP предлагает уже 99,9% того, что вам нужно в течение SplFileObject
Вы добавляете недостающие 0,1%, расширяя его. В следующем примере CSVFile
вытекает из этого:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line)
{
var_dump($line);
}
С данными вашего примера:
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "1500"
["Note"]=> string(6) "loaded"
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(4) "2500"
["Note"]=> string(0) ""
}
array(3) {
["Make"]=> string(5) "Chevy"
["Model"]=> string(0) ""
["Note"]=> string(6) "loaded"
}
CSVFile
определяется как следующее:
class CSVFile extends SplFileObject
{
private $keys;
public function __construct($file)
{
parent::__construct($file);
$this->setFlags(SplFileObject::READ_CSV);
}
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
Если вы сделаете это таким образом, все детали будут просто заключены в капсулу. Кроме того, с ошибками (например, несовпадением счетчиков) легче справиться current()
функция, поэтому код, который использует данные, не должен иметь дело с этим.
Редактировать:
Однако приведенный пример является коротким с точки зрения повторного использования. Вместо расширения из SplFileObject его гораздо лучше агрегировать:
class KeyedArrayIterator extends IteratorIterator
{
private $keys;
public function rewind()
{
parent::rewind();
$this->keys = parent::current();
parent::next();
}
public function current()
{
return array_combine($this->keys, parent::current());
}
public function getKeys()
{
return $this->keys;
}
}
Код идентичен, но детали, которые были заключены в конструкторе, не учитываются. Это сокращение позволяет использовать тип более широко, например, с (но не только с) указанным SplFileObject:
$file = new SplFileObject('../data/test.csv');
$file->setFlags($file::READ_CSV);
$csv = new KeyedArrayIterator($file);
foreach ($csv as $line) {
var_dump($line);
}
Если теперь это звучит слишком многословно, его снова можно обернуть, чтобы придать ему более приятный вид:
class CSVFile extends KeyedArrayIterator
{
/**
* @param string $file
*/
public function __construct($file)
{
parent::__construct(new SplFileObject($file));
$this->setFlags(SplFileObject::READ_CSV);
}
}
Благодаря стандартной возможности украшения TraversableIterator исходный код конструктора из первого примера CSVFile может быть скопирован на 100%.
Последнее добавление также позволяет сохранить исходный код, который использует итератор CSVFile:
$csv = new CSVFile('../data/test.csv');
foreach ($csv as $line) {
var_dump($line);
}
Так что просто быстрый рефакторинг, чтобы позволить больше повторного использования кода. Вы получаете KeyedArrayIterator бесплатно.
$csv_data = array_map('str_getcsv', file('Book.csv'));// reads the csv file in php array
$csv_header = $csv_data[0];//creates a copy of csv header array
unset($csv_data[0]);//removes the header from $csv_data since no longer needed
foreach($csv_data as $row){
$row = array_combine($csv_header, $row);// adds header to each row as key
var_dump($row);//do something here with each row
}
function processCsv($absolutePath)
{
$csv = array_map('str_getcsv', file($absolutePath));
$headers = $csv[0];
unset($csv[0]);
$rowsWithKeys = [];
foreach ($csv as $row) {
$newRow = [];
foreach ($headers as $k => $key) {
$newRow[$key] = $row[$k];
}
$rowsWithKeys[] = $newRow;
}
return $rowsWithKeys;
}
Попробуй это
$csv = array_map("str_getcsv", file('file.csv', FILE_SKIP_EMPTY_LINES));
$header = array_shift($csv); // get header from array
foreach ($csv as $key => $value) {
$csv[$key] = array_combine($header, $value);
var_dump($csv[$key]['Model']);
}
var_dump($csv);
На данный момент я предполагаю, что вы уже решили проблему, но подумал, что я бы предложил это, вероятно, не самое лучшее / изящное решение, но оно решает проблему:
$row = 1;
$array = array();
$marray = array();
$handle = fopen('file.csv', 'r');
if ($handle !== FALSE) {
while (($data = fgetcsv($handle, 0, ',')) !== FALSE) {
if ($row === 1) {
$num = count($data);
for ($i = 0; $i < $num; $i++) {
array_push($array, $data[$i]);
}
}
else {
$c = 0;
foreach ($array as $key) {
$marray[$row - 1][$key] = $data[$c];
$c++;
}
}
$row++;
}
echo '<pre>';
print_r($marray);
echo '</pre>';
}
Функция array_combine() работает только в том случае, если столбцы заголовков соответствуют столбцам данных, в противном случае выдается ошибка.
В ответе Тима Купера выше, а не
$all_rows = array();
$header = null;
while ($row = fgetcsv($file)) {
if ($header === null) {
$header = $row;
continue;
}
$all_rows[] = array_combine($header, $row);
}
Я бы написал более элегантным и эффективным способом:
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
Попробуйте с этим кодом:
$query = "SELECT * FROM datashep_AMS.COMPLETE_APPLICATIONS";
$export= mysql_query($query);
$first = true;
$temp = $export[0];
//echo "<pre>"; print_r($first); exit;
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename=file.csv');
header('Pragma: no-cache');
header("Expires: 0");
$outstream = fopen("php://output", "w");
foreach($export as $result)
{
if($first){
$titles = array();
foreach($temp as $key=>$val){
$titles[] = $key;
}
//print_r ($titles);exit;
fputcsv($outstream, $titles);
}
$first = false;
fputcsv($outstream, $result);
}
fclose($outstream);
Спасибо