2012-04-16 22 views
15

Tengo un CSV con la primera fila que contiene los nombres de campo. Ejemplo de datos es ...Procesar CSV en matriz con encabezados de columna para clave

"Make","Model","Note" 
"Chevy","1500","loaded" 
"Chevy","2500","" 
"Chevy","","loaded" 

necesito mis datos formateados en un array de pares clave-valor, donde el nombre de clave es el título de la columna. Supongo que sería algo como esto para la fila 1:

$array = [ 
    "Make" => "Chevy", 
    "Model" => "1500", 
    "Note" => "loaded" 
]; 

... la fila 2 ...

$array = [ 
    "Make" => "Chevy", 
    "Model" => "1500", 
    "Note" => "" 
]; 

... y la fila 3 ...

$array = [ 
    "Make" => "Chevy", 
    "Model" => "", 
    "Note" => "loaded" 
]; 

I 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.

Sus ideas son muy apreciadas.

+0

probablemente significará 2500 en el segundo ejemplo de matriz – user1899415

Respuesta

39
$all_rows = array(); 
$header = fgetcsv($file); 
while ($row = fgetcsv($file)) { 
    $all_rows[] = array_combine($header, $row); 
} 
print_r($all_rows); 
+0

Gracias por la pronta respuesta. Esto está cerca, aunque estoy terminando con datos en las teclas. No ve ningún encabezado de columna en ninguna de las matrices que se devuelven. –

+1

@BitBucket: Si haces un volcado de los datos que están en '$ all_rows', deberías ver una matriz con sub-arrays que tienen los datos del encabezado como claves. –

+0

tenga en cuenta que deberá ejecutar $ encabezado cuando lo cree por primera vez para asegurarse de proporcionarle a las columnas sin títulos datos ficticios como "desconocido". $ x o la matriz combinada será de diferentes longitudes – Titan

27

PHP ofrece ya el 99,9% de lo que necesita dentro de SplFileObject, se agrega la falta 0,1% mediante la extensión de la misma. En el siguiente ejemplo CSVFile se extiende desde ella:

$csv = new CSVFile('../data/test.csv'); 

foreach ($csv as $line) 
{ 
    var_dump($line); 
} 

Con los datos del 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 la 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, el los detalles están muy bien encapsulados. Además, es más fácil tratar los 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 necesita tratar con él.

Editar:

Sin embargo, el ejemplo dado es corto en términos de re-usablity. En lugar de que se extiende desde SplFileObject que es mucho mejor para agregarla:

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 fueron encapsulados en el constructor se quedan fuera. Esta reducción permite usar el tipo de manera más amplia, p.con (pero no sólo con) el dijo 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 prolijo, de nuevo se puede envolver para dar de nuevo una fachada más bonita:

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 podría copiarse solo al 100%.

Este último además también permite mantener el código original que utiliza la CSVFile iterador intacta:

$csv = new CSVFile('../data/test.csv'); 

foreach ($csv as $line) { 
    var_dump($line); 
} 

lo tanto, sólo una refactorización rápida para permitir una mayor reutilización de códigos. Obtiene un KeyedArrayIterator de forma gratuita.

+1

muy bonita ...... –

+0

¿Podría pensar de la manera de hacer esto manejar CSV sin cabeza por el bien de interés? –

+1

Eso es bastante directo: Deje de lado la función 'rewind' y pase las claves en el constructor. Si necesitas más flexibilidad, he puesto un código en una esencia con ejemplos, pero sigue siendo bastante alfa: https://gist.github.com/4153380 – hakre

0

intento 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

2
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; 
} 
1

En este punto estoy asumiendo que ya ha resuelto el problema, pero pensé en tirar de una manera sugerida en torno a este , probablemente no es la mejor solución/más elegante, pero no el truco:

$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>'; 
} 
4
$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 
} 
0

probar este

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

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

Me código, de una manera más elegante y eficiente:

$all_rows = array(); 
$header = fgetcsv($file); 
while ($row = fgetcsv($file)) { 
    $all_rows[] = array_combine($header, $row); 
} 
Cuestiones relacionadas