CSV în matrice asociativă (Programare, Php, Array-Uri, Csv, Asociativ)

ParoX a intrebat.
a intrebat.

Am văzut numeroase exemple despre cum se poate lua un fișier CSV și apoi să se creeze un array asociativ cu antetele ca și chei.

De exemplu:

Brand,Model,Part,Test
Honda,Civic,123,244
Honda,Civic,135,434
Toyota,Supra,511,664

În cazul în care s-ar crea o matrice de genul Array[$num][$key] unde $key ar fi Brand, Model, Part, Test.

Astfel, dacă aș dori să accesez valoarea testului „434”, ar trebui să fac o buclă cu fiecare index din matrice și apoi să ignor toate mărcile care nu sunt honda și toate modelele care nu sunt Civic.


Ceea ce trebuie să fac este să accesez valoarea cel mai direct, în loc să trec printr-o buclă for care trece prin fiecare index $num. Vreau să pot accesa valoarea testului „434” cu:

Array['Honda']['Civic']['135']

sau să controlez o instrucțiune for cu parcurgerea în buclă a fiecărui model pe care îl are Honda… ceva de genul

foreach $model in Array['Honda']

Cel puțin, trebuie să pot trece prin fiecare model, având în vedere o marcă cunoscută, și să accesez toate informațiile relative la fiecare.

Editați:

Doar pentru a confirma că am fost înființat acest lucru un exemplu. Datele mele actuale au anteturi de genul::

brand model part price shipping description footnote

Din care am nevoie să accesez toate informațiile legate de piesă (preț, transport, descriere, notă de subsol).

Comentarii

  • Exemplu(e) cum să fac asta cu SplFileInfo –  > Por hakre.
6 răspunsuri
Haim Evgi

rulați peste fișierul csv linie cu linie și introduceți la matrice ca:

$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
";
    }
    fclose($handle);
}

Comentarii

    16

  • Dacă ar fi să schimbi $array[$i][$k] = $valoare; în $array[$i][$fields[$k]] = $valoare; vei obține antetul ca și cheie. –  > Por Craig Hooghiem.
  • Tocmai voiam să spun același lucru ca @CraigHooghiem înainte de a vedea comentariul său. Cu $fields[$k], răspunsul de mai sus funcționează așa cum era de așteptat. –  > Por DWils.
  • Dacă spațiile albe din jurul valorilor rândului de antet reprezintă o preocupare, puteți curăța cu $fields = array_map('trim', $row); –  > Por jerrygarciuh.
Daerik

Prea multe soluții lungi. Întotdeauna am considerat că aceasta este cea mai simplă:

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

Comentarii

  • cod minunat, funcționează foarte bine cu csv separat prin virgulă. Dar ce se întâmplă dacă este un csv separat cu punct și virgulă? Nu găsesc modalitatea de a face același lucru cu un csv separat de punct și virgulă. –  > Por Alex.
  • @Alex, pe lângă faptul că ne certăm din punct de vedere semantic cu privire la acronimul CSV fiind Comma Separated Values, aveți posibilitatea de a seta delimitatorul din str_getcsv funcție. Sper că acest lucru vă ajută! –  > Por Daerik.
  • Dacă doriți să treceți un parametru (cum ar fi delimitatorul) la str_getcsv, utilizați acest lucru: $rows = array_map(function($row) { return str_getcsv($row, ';'); }, file('file.csv')); –  > Por marcovtwout.
  • @marcovtwout, țineți cont de faptul că puteți trece argumente suplimentare ca al treilea parametru al lui array_map(). –  > Por Daerik.
  • această soluție este potențial foarte mare consumatoare de memorie, deoarece creează un array care conține întregul fișier CSV, în loc să citească linii individuale în memorie –  > Por AngryUbuntuNerd.
mario

Pentru a crea o matrice de listă asociativă folosiți ceva de genul

$keys = fgetcsv($f);
while (!feof($f)) {
    $array[] = array_combine($keys, fgetcsv($f));
}

Și pentru a parcurge și filtra după anumite atribute scrieți o funcție de genul::

function find($find) {
    foreach ($array as $row) {
         if (array_intersect_assoc($row, $find) == $find) {
             $result[] = $row;
         }
    }
}

În cazul în care o veți invoca cu $find = array(Brand=>Honda, Model=>Civic, Part=>135) pentru a filtra modelele căutate. Cealaltă structură de matrice pozițională nu pare să funcționeze foarte bine, cu excepția cazului în care doriți să accesați doar atributul „Test”.

Tom Carnell

Încercați acest algoritm simplu:

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

Comentarii

  • Acestui răspuns îi lipsește explicația educațională. –  > Por mickmackusa.
Brad

Iată o soluție care va funcționa prin specificarea unui fișier local sau a unui URL. De asemenea, puteți activa și dezactiva asocierea. Sperăm că acest lucru vă ajută.

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

Încercați această utilizare:

$o=new CSVData();
$o->getData('/home/site/datafile.csv');
$data=$o->data;
print_r($data);

mickmackusa

Utilizând fgetcsv() pare a fi cel mai direct și mai sensibil instrument pentru această sarcină.

conținutul csv.csv:

Brand,Model,Part,Test
Honda,Civic,123,244
Honda,Civic,135,434
Toyota,Supra,511,664

Cod:

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

Ieșire:

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',
  ),
)

Resurse: http://php.net/manual/en/function.fgetcsv.php