2012-04-16 2 views
15

У меня есть 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" 
]; 

I «Не знаю, как это сделать, кроме статики - проблема заключается в том, что столбцы со связанными данными могут меняться от одного файла к следующему ... столбцы, переупорядоченные, сброшенные или добавленные.

Ваши идеи очень ценятся.

+0

вы, вероятно, означает, 2500 во втором примере массива – user1899415

ответ

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

Спасибо за быстрый ответ. Это близко, хотя я получаю данные в ключах. Не просматривайте заголовки столбцов в любом из возвращаемых массивов. –

+1

@BitBucket: Если вы делаете дамп данных, которые находятся в '$ all_rows', вы должны увидеть массив с суб-массивами, которые имеют данные заголовка в виде ключей. –

+0

Обратите внимание, что вам нужно будет запустить через $ header, когда вы сначала создадите его, чтобы убедиться, что вы даете какие-либо столбцы без фиктивных данных, таких как «unknown». $ x или массив объединяются будут разные длины – Titan

27

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(), поэтому код, который использует данные, не нуждается в том, чтобы справляться с этим.

Edit:

Однако приведенный пример короток с точкой зрения повторного usablity. Вместо того, простирающейся от 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.

+1

очень приятно ...... –

+0

Не могли бы вы подумать о том, как сделать этот дескриптор без заголовка CSVs ради интереса? –

+1

Это довольно прямолинейно: оставьте функцию 'rewind' и вместо этого передайте ключи в конструкторе. Если вам нужна большая гибкость, я привел некоторые примеры кода в примеры, но это все еще довольно альфа: https://gist.github.com/4153380 – hakre

0

Try с этим кодом:

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

Благодаря

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

На данный момент я предполагаю, что вы уже решили эту проблему, но думали, что я бросить в предложенном пути вокруг этого , вероятно, не лучший/наиболее элегантное решение, но это делает трюк:

$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

Попробуйте

$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

В ответ Тим ​​Купер выше, вместо

$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); 
} 
Смежные вопросы