CSV to Associative Array

78,079

Solution 1

run over the csv file line by line, and insert to array like:

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

Solution 2

Too many long solutions. I've always found this to be the simplest:

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

Solution 3

To create an associative list array use something like:

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

And to traverse and filter by specific attributes write a function like:

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

Where you would invoke it with $find = array(Brand=>Honda, Model=>Civic, Part=>135) to filter out the searched models. The other positional array structure seems not very workable, unless you only want to access the "Test" attribute.

Solution 4

Try this simple algorithm:

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

Solution 5

Using fgetcsv() seems the most direct and sensible tool for the job.

csv.csv contents:

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

Code:

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

Output:

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

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

Share:
78,079
ParoX
Author by

ParoX

Updated on July 17, 2022

Comments

  • ParoX
    ParoX almost 2 years

    I've seen numerous examples on how to take a CSV file and then create an associative array with the headers as the keys.

    For example:

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

    Where it would create an Array such as Array[$num][$key] where $key would be Brand, Model, Part, Test.

    So If I wanted to access the test value "434" I would have to loop every index in the array and then ignore any Brands that were not honda, and any models that were not Civic


    What I need to do is access the value most directly, instead of running through a for loop going through each $num index. I want to be able to access the value test "434" with:

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

    or control a for statement with looping through every model Honda has... something like

    foreach $model in Array['Honda']

    At the very least I need to be able to go through every model given a known Brand and access all the relative info for each.

    Edit:

    Just to confirm I was setting this up an example. My actually data has headers like:

    brand model part price shipping description footnote

    Of which I need to access all the information tied to the part (price, shipping,desc, footnote)

  • Craig Hooghiem
    Craig Hooghiem almost 11 years
    If you were to change $array[$i][$k] = $value; to $array[$i][$fields[$k]] = $value; you would get the header as the key.
  • DWils
    DWils about 10 years
    I was just about to say the same as @CraigHooghiem before I saw his comment. With $fields[$k], the above answer works as expected.
  • Alex
    Alex over 6 years
    marvelous code, it works great with comma separated csv. But what if it is a semicolon separated csv? I don't find the way to do the same with a semicolon separated csv.
  • Daerik
    Daerik over 6 years
    @Alex, besides arguing semantics on the acronym CSV being Comma Separated Values, you are able to set the delimiter of the str_getcsv function. I hope this helps!
  • marcovtwout
    marcovtwout over 6 years
    If you want to pass a parameter (like the delimiter) to str_getcsv, use this: $rows = array_map(function($row) { return str_getcsv($row, ';'); }, file('file.csv'));
  • Daerik
    Daerik over 6 years
    @marcovtwout, keep in mind that you can pass additional arguments as the third parameter of array_map().
  • dsharhon
    dsharhon almost 6 years
    For CSV in a string: $rows = array_map('str_getcsv', preg_split('/\r\n|\r|\n/', $string));
  • AngryUbuntuNerd
    AngryUbuntuNerd over 5 years
    this solution is potentially very memory hungry, as it creates an array containing the whole of the CSV file, instead of reading single lines into memory
  • jerrygarciuh
    jerrygarciuh about 5 years
    If whitespace around header row values is a concern you can clean with $fields = array_map('trim', $row);
  • Brian Stinar
    Brian Stinar over 4 years
    I like this, but the lack of error handling at all makes this simpler-appearing than I felt comfortable with. I added additional checking to make sure the file opened correctly. I still think it's simpler than the other solutions here, so thanks!
  • Gsinti
    Gsinti over 4 years
    Why use a foreach when array_map works and keeps things consistent? $csv = array_map(function($row) use ($header) { return array_combine($header, $row); }, $rows);
  • Dan
    Dan about 4 years
    Why doe the first field's header have double quotes around double quotes? "LastName" in CSV becomes ""LastName"" as a header
  • mickmackusa
    mickmackusa over 3 years
    This answer is missing its educational explanation.
  • wivku
    wivku over 2 years
    The foreach can be simplified these days: $csv = array_map(fn($e) => array_combine($header, $e), $rows);
  • Richard
    Richard over 2 years
    Tip: if you use a zero (0) instead of 1000 here: fgetcsv($handle, 0, ","), then there is no character limit per line. Good for if you aren't sure just how many characters might be per line.
  • user2280032
    user2280032 about 2 years
    I have found the foreach to run one more time after all data is parsed causing the last entry to simply be false, this causes issues when then iterating and expecting keys to be present. A for loop with count(rows) would probably be better here.