php - guia - qgis manual
Procesar CSV en matriz con encabezados de columna para clave (8)
Tengo un CSV con la primera fila que contiene los nombres de los campos. Los datos de ejemplo son ...
"Make","Model","Note"
"Chevy","1500","loaded"
"Chevy","2500",""
"Chevy","","loaded"
Necesito mis datos formateados en una matriz de pares clave-valor donde el nombre de la clave es el encabezado de la columna. Supongo que sería algo así para la fila 1:
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => "loaded"
];
... fila 2 ...
$array = [
"Make" => "Chevy",
"Model" => "1500",
"Note" => ""
];
... y la fila 3 ...
$array = [
"Make" => "Chevy",
"Model" => "",
"Note" => "loaded"
];
No estoy seguro de cómo hacer esto de forma no estática: el problema es que las columnas con sus datos asociados podrían cambiar de un archivo al siguiente ... columnas reorganizadas, eliminadas o agregadas.
Tus ideas son muy apreciadas.
En este punto supongo que ya has resuelto el problema, pero pensé que lo haría de forma sugerida, probablemente no sea la mejor solución ni la más elegante, pero funciona:
$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>'';
}
En la respuesta de Tim Cooper anterior, en lugar de
$all_rows = array();
$header = null;
while ($row = fgetcsv($file)) {
if ($header === null) {
$header = $row;
continue;
}
$all_rows[] = array_combine($header, $row);
}
Codificaría de una manera más elegante y eficiente:
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
PHP ofrece ya el 99,9% de lo que necesitas dentro de SplFileObject
, agregas el 0,1% faltante al extenderlo. En el siguiente ejemplo, CSVFile
extiende desde allí:
$csv = new CSVFile(''../data/test.csv'');
foreach ($csv as $line)
{
var_dump($line);
}
Con su información de ejemplo:
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
se define como el siguiente:
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;
}
}
Si lo haces de esta manera, los detalles estarán encapsulados. Además, es más fácil lidiar con errores (por ejemplo, desajuste de cuenta) dentro de la función current()
por lo que el código que hace uso de los datos no tiene que tratar con él.
Editar:
Sin embargo, el ejemplo dado es corto en términos de re-usablity. En lugar de extender desde SplFileObject , es mucho mejor agregarlo:
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;
}
}
El código es idéntico pero los detalles que se encapsularon en el constructor se omiten. Esta reducción permite usar el tipo más ampliamente, por ejemplo con (pero no solo con) dicho dicho SplFileObject :
$file = new SplFileObject(''../data/test.csv'');
$file->setFlags($file::READ_CSV);
$csv = new KeyedArrayIterator($file);
foreach ($csv as $line) {
var_dump($line);
}
Si eso ahora suena demasiado detallado, de nuevo se puede envolver para darle nuevamente una fachada más agradable:
class CSVFile extends KeyedArrayIterator
{
/**
* @param string $file
*/
public function __construct($file)
{
parent::__construct(new SplFileObject($file));
$this->setFlags(SplFileObject::READ_CSV);
}
}
Gracias a la capacidad de decoración estándar de TraversableIterator , el código de constructor original del primer ejemplo de CSVFile solo pudo copiarse al 100%.
Esta última adición también permite mantener intacto el código original que usa el iterador CSVFile :
$csv = new CSVFile(''../data/test.csv'');
foreach ($csv as $line) {
var_dump($line);
}
Tan solo una refactorización rápida para permitir más reutilización de código. Obtienes un KeyedArrayIterator gratis.
Prueba esto
$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);
Pruebe con este código:
$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);
Gracias
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;
}
$all_rows = array();
$header = fgetcsv($file);
while ($row = fgetcsv($file)) {
$all_rows[] = array_combine($header, $row);
}
print_r($all_rows);
$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
}