使用列标题将CSV处理为数组

时间:2012-04-16 20:16:14

标签: php arrays csv heading

我有一个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"
];

我不确定除了静态之外该怎么做 - 问题是带有相关数据的列可能会从一个文件更改为下一个...重新排列,删除或添加的列。

非常感谢您的想法。

9 个答案:

答案 0 :(得分:46)

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

答案 1 :(得分:32)

PHP在SplFileObject中提供了99.9%的所需内容,您可以通过扩展来添加缺少的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()函数内的错误(例如计数不匹配),因此使用数据的代码不需要处理它。

<强> 编辑:

然而,给出的例子在重新使用方面很短。而不是从 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%复制。

最后一次添加还可以保持使用 CSV文件迭代器的原始代码保持不变:

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

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

因此,只需快速重构即可实现更多的代码重用。您可以免费获得 KeyedArrayIterator

答案 2 :(得分: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
}

答案 3 :(得分: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;
}

答案 4 :(得分: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>';
}

答案 5 :(得分:0)

尝试使用此代码:

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

由于

答案 6 :(得分: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);

答案 7 :(得分:0)

在上面的Tim Cooper的回答中,而不是

$(function() {

    $('.dropdown').each(function() {
        var val = '';
        var $dropdown = $(this);
        var $list = $dropdown.find('ul');
        $dropdown.on('show.bs.dropdown', function() {
            $(document.body).on('keyup', typing);
            $list.find('a').css({ background: 'transparent' });
        });

        $dropdown.on('hide.bs.dropdown', function() {
            $(document.body).off('keyup', typing);
            val = '';
            $list.find('a').css({ background: 'transparent' });
        });

        function typing(e, alreadyChecked) { // we use alreadyChecked to break out of typing
            $list.find('a').css({ background: 'transparent' });
            if (e.keyCode === 8 && val.length > 1) { // This part allows backspace to delete previous characters entered
                val = val.split('').splice(0, val.length - 1).join('');
            } else if (e.key && e.key.length === 1) { // e.key.length === 1 this was adeed because of buttons like tab,alt,backspace etc. because they create infinite loop and exceed threads
                val += e.key.toLowerCase();
            } else {
                return;
            }
            console.log(e);
            if (val.length === 0) {
                return;
            }
            var els = $list.find('a').get().filter(function(node) {
                return $(node).text().toLowerCase().indexOf(val) === 0;
            });
            if (!els || els.length === 0) {
                val = '';
                if (alreadyChecked) {
                    typing(e, true);
                }
                return;
            }
            var scrollTop = $list[0].scrollTop;
            $list[0].scrollTop = scrollTop + $(els[0]).position().top - $(els[0]).height();
            $(els).css({ background: 'rgba(255, 171, 0, 0.3)' });
        }
    });

});

我会以更优雅高效的方式编码:

$all_rows = array();
$header = null;
while ($row = fgetcsv($file)) {
    if ($header === null) {
        $header = $row;
        continue;
    }
    $all_rows[] = array_combine($header, $row);
}

答案 8 :(得分:0)

array_combine()函数仅在标题列与数据列匹配时才起作用,否则会引发错误。