【问题标题】:PHP CSV merge two CSV files when there is same data in both files' rows当两个文件的行中有相同的数据时,PHP CSV 合并两个 CSV 文件
【发布时间】:2020-12-13 17:01:30
【问题描述】:

我有这样的 csv01:

A    |  B   |   C     |  D 
-----------------------------
905  |  bla |   meh?  |  na
16   |  meh |   meh?  |  ni
4    |  bla |   meh?  |  put

我有这样的 csv02:

A    |  Z   |   Y     
---------------------
4    |  info |  meh   
16   |  info |  meh   
905  |  info |  meh  

如何根据两个文件中的 A 列数字获取信息?

这些数字在两个文件中,顺序不同。有时数据是空白的,因此它可能会在这种情况下输出空白或“空”结果。

A    |  B   |   C     |  D     |  Z   
-------------------------------------
905  |  bla |   meh?  |  na   |  info
16   |  meh |   meh?  |  ni   |  info
4    |  bla |   meh?  |  put  |  info

我要做的是根据匹配的数字值合并两个 CSV(值相同时每列的值):905 ,16 ,4...

我试过但没有得到任何结果,它只在一行上输出了一些不正确的数据:

<?php
   $fh = fopen('csv1.csv', 'r');
        $fhg = fopen('csv2.csv', 'r');
         while (($data = fgetcsv($fh, 0, ",")) !== FALSE) {
            $csv1[3]=$data;
        }
        while (($data = fgetcsv($fhg, 0, ",")) !== FALSE) {
                $csv2[0]=$data;
        }

        for($x=0;$x< count($csv2);$x++)
        {
            if($x==0){
                unset($csv1[0][3]);
                $line[$x]=array_merge($csv2[0],$csv1[3]); //header
            }
            else{
                $deadlook=0;
                for($y=0;$y <= count($csv1);$y++)
                {
                    if($csv1[$y][3] == $csv2[$x][0]){
                        unset($csv1[$y][3]);
                        $line[$x]=array_merge($csv2[$x],$csv1[$y]);
                        $deadlook=1;
                    }
                }
                if($deadlook==0)
                    $line[$x]=$csv2[$x];
            }
        }

        $fp = fopen('final.csv', 'w');//output file set here

        foreach ($line as $fields) {
            fputcsv($fp, $fields);
        }
        fclose($fp);
?>

一直在尝试使用 fgetcsv 并使用过密钥。我放弃了我的代码根本不起作用。关于如何实现这一目标的任何想法?

【问题讨论】:

  • $csv1[3]$csv2[0] 只会给你一个值。您需要保持一个文件处于打开状态,并在该文件的迭代过程中引入另一个文件并搜索您的值。这将占用大量资源。可能这应该放入数据库中,或者作为起点存储在数据库中。使用数据库,这只是join table using(A)
  • 我会尝试使用 python 和 panda ,因为我恰好安装了这些。这应该会有所帮助:stackoverflow.com/questions/54383305/…

标签: php csv php-7 array-merge fputcsv


【解决方案1】:

这在 PHP 中可以相对容易地完成,不需要 Python 的 Pandas。

a.csv:

905,bla,meh?,na3
16,meh,meh?,ni2
4,bla,meh?,put1

b.csv:

4,info,meh1
16,info,meh2
905,info,meh3
<?php

// load both files to array
$a = array_map('str_getcsv', file('a.csv'));
$b = array_map('str_getcsv', file('b.csv'));

var_dump($a, $b);

// index both arrays by the column you want to merge by
$mergeColumn = 0;
$a = array_combine(array_column($a, $mergeColumn), $a);
$b = array_combine(array_column($b, $mergeColumn), $b);

var_dump($a, $b);

// construct combined array by combining same indexes from both arrays
// and merging the values (skip merge column from second file so it is not doubled)
$c = [];
foreach ($a as $k => $dataA) {
  unset($b[$k][$mergeColumn]);
  $c[$k] = array_merge($dataA, $b[$k]);
}

var_dump($c);

// put it to output csv file
$fp = fopen('c.csv', 'w');
foreach ($c as $row) {
    fputcsv($fp, $row);
}
fclose($fp);

输出:

// a.csv as array
array(3) {
  [0]=>
  array(4) {
    [0]=>
    string(3) "905"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "na3"
  }
  [1]=>
  array(4) {
    [0]=>
    string(2) "16"
    [1]=>
    string(3) "meh"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "ni2"
  }
  [2]=>
  array(4) {
    [0]=>
    string(1) "4"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(4) "put1"
  }
}

// b.csv as array
array(3) {
  [0]=>
  array(3) {
    [0]=>
    string(1) "4"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh1"
  }
  [1]=>
  array(3) {
    [0]=>
    string(2) "16"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh2"
  }
  [2]=>
  array(3) {
    [0]=>
    string(3) "905"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh3"
  }
}

// a.csv keyed by merge column
array(3) {
  [905]=>
  array(4) {
    [0]=>
    string(3) "905"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "na3"
  }
  [16]=>
  array(4) {
    [0]=>
    string(2) "16"
    [1]=>
    string(3) "meh"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "ni2"
  }
  [4]=>
  array(4) {
    [0]=>
    string(1) "4"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(4) "put1"
  }
}

// b.csv keyed by merge column
array(3) {
  [4]=>
  array(3) {
    [0]=>
    string(1) "4"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh1"
  }
  [16]=>
  array(3) {
    [0]=>
    string(2) "16"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh2"
  }
  [905]=>
  array(3) {
    [0]=>
    string(3) "905"
    [1]=>
    string(4) "info"
    [2]=>
    string(4) "meh3"
  }
}

// combined array
array(3) {
  [905]=>
  array(6) {
    [0]=>
    string(3) "905"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "na3"
    [4]=>
    string(4) "info"
    [5]=>
    string(4) "meh3"
  }
  [16]=>
  array(6) {
    [0]=>
    string(2) "16"
    [1]=>
    string(3) "meh"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(3) "ni2"
    [4]=>
    string(4) "info"
    [5]=>
    string(4) "meh2"
  }
  [4]=>
  array(6) {
    [0]=>
    string(1) "4"
    [1]=>
    string(3) "bla"
    [2]=>
    string(4) "meh?"
    [3]=>
    string(4) "put1"
    [4]=>
    string(4) "info"
    [5]=>
    string(4) "meh1"
  }
}

和 c.csv(结果):

905,bla,meh?,na3,info,meh3
16,meh,meh?,ni2,info,meh2
4,bla,meh?,put1,info,meh1

如果两个文件具有相同的标识符(第一列),则上述解决方案有效 如果在其他 csv 文件中可能存在不匹配的行,则需要另一种方法。

a.csv:

A,B,C,D
905,bla,meh?,na3
16,meh,meh?,ni2
4,bla,meh?,put1
1,a,b,c

b.csv:

A,Z,Y
4,info,meh1
16,info,meh2
905,info,meh3
2,d,e

a.csv 包含 A: 1 的行,在 b.csv 中没有匹配。 b.csv 包含 A: 2 的行,在 a.csv 中没有匹配项。 我们希望结果 csv 有 5 行(4、16、905 - common + 1 with empty Z,Y + 2 with empty B,C,D)。

代码:

<?php

$a = parseCsv('a.csv');
$b = parseCsv('b.csv');

$allHeaders = array_unique(array_merge($a['header'], $b['header']));

$mergeColumn = 'A';
$a['rows'] = array_combine(array_column($a['rows'], $mergeColumn), $a['rows']);
$b['rows'] = array_combine(array_column($b['rows'], $mergeColumn), $b['rows']);

$allIndexes = array_unique(array_merge(array_column($a['rows'], $mergeColumn), array_column($b['rows'], $mergeColumn)));

$c = [];
foreach ($allIndexes as $index) {
  $row = [];
  foreach ($allHeaders as $header) {
    $row[$header] = '';
    if (isset($a['rows'][$index][$header])) {
      $row[$header] = $a['rows'][$index][$header];
    } elseif (isset($b['rows'][$index][$header])) {
      $row[$header] = $b['rows'][$index][$header];
    }
  }

  $c[$index] = $row;
}

var_dump($c);

$fp = fopen('c.csv', 'w');
fputcsv($fp, $allHeaders);
foreach ($c as $row) {
    fputcsv($fp, $row);
}
fclose($fp);


function parseCsv(string $file): array {
  $rows = array_map('str_getcsv', file($file));
  $header = array_shift($rows);
  $csv = [];
  foreach($rows as $row) {
    $csv[] = array_combine($header, $row);
  }

  return ['header' => $header, 'rows' => $csv];
}

输出:

array(5) {
  [905]=>
  array(6) {
    ["A"]=>
    string(3) "905"
    ["B"]=>
    string(3) "bla"
    ["C"]=>
    string(4) "meh?"
    ["D"]=>
    string(3) "na3"
    ["Z"]=>
    string(4) "info"
    ["Y"]=>
    string(4) "meh3"
  }
  [16]=>
  array(6) {
    ["A"]=>
    string(2) "16"
    ["B"]=>
    string(3) "meh"
    ["C"]=>
    string(4) "meh?"
    ["D"]=>
    string(3) "ni2"
    ["Z"]=>
    string(4) "info"
    ["Y"]=>
    string(4) "meh2"
  }
  [4]=>
  array(6) {
    ["A"]=>
    string(1) "4"
    ["B"]=>
    string(3) "bla"
    ["C"]=>
    string(4) "meh?"
    ["D"]=>
    string(4) "put1"
    ["Z"]=>
    string(4) "info"
    ["Y"]=>
    string(4) "meh1"
  }
  [1]=>
  array(6) {
    ["A"]=>
    string(1) "1"
    ["B"]=>
    string(1) "a"
    ["C"]=>
    string(1) "b"
    ["D"]=>
    string(1) "c"
    ["Z"]=>
    string(0) ""
    ["Y"]=>
    string(0) ""
  }
  [2]=>
  array(6) {
    ["A"]=>
    string(1) "2"
    ["B"]=>
    string(0) ""
    ["C"]=>
    string(0) ""
    ["D"]=>
    string(0) ""
    ["Z"]=>
    string(1) "d"
    ["Y"]=>
    string(1) "e"
  }
}

c.csv:

905,bla,meh?,na3,info,meh3
16,meh,meh?,ni2,info,meh2
4,bla,meh?,put1,info,meh1
1,a,b,c,,
2,,,,d,e

【讨论】:

  • 出了点问题,我得到 'Undefined index: ...' 因为第 18 行:foreach ($a as $k => $dataA) { unset($b[$k][$合并列]); $c[$k] = array_merge($dataA, $b[$k]); }
  • 您发布了 3 行,那么是哪一行?这是带有上面输入文件的独立脚本,它不会发出任何警告 - 所以它要么是你的 csvs 要么是你所做的一些更改 - 所以如果没有代码,我无法真正回答这个问题
  • 此行导致错误“注意:未定义的索引:...” $c[$k] = array_merge($dataA, $b[$k]); . CSV 文件没有完全相同的行数。但是具有相同的列数,并且每个 csv 中的第一列是“键”数。 (并不总是在其他 csv 文件中)。这是我从记事本 pastebin.com/K82BnViQ 复制/粘贴的 CSV (我也尝试用 $mergeColumn = 1; 替换 $mergeColumn = 0; 然后它说:警告:array_combine():两个参数应该有相同的数字元素。),我已经放回 $mergeColumn = 0;但仍然遇到索引问题。
  • 你写了“这些数字在两个文件中”,所以我假设两个文件都包含我们匹配它们的相同列(但顺序可以不同)。我使用第二种解决方案制作和编辑,其中第二个文件中可能存在不匹配的行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 2015-01-18
  • 2020-03-22
相关资源
最近更新 更多