1

ヘッダー行を持つタブ区切り値 (TSV) ファイルを想定すると、ヘッダー フィールドをキーとし、データ フィールドをデータとする PHP 配列を作成するにはどうすればよいでしょうか?

$txtArray にファイル内のすべての行が含まれていると仮定すると、

$hdrArray = explode( "\t", $txtArray[0]);
$i = 0;
foreach ($hdrArray as $hdr) {
  $heads[$hdr] = '';
  $headerNames[$i++] = $hdr;
}
for ($i = 1; $i < (count($txtArray) - 1); $i++ ) {
  $datArray = explode( "\t", $txtArray[$i]);
  if (count($datArray) > 1) {
    for($j = 0; $j < count($datArray); $j++) {
      $heads[$headerNames[$j]] = $datArray[$j];
    }
  }
  # process the line
}

ファイルの各行のすべてのフィールドの field_name => field_data を含む $heads があります。これをコーディングするより良い方法はありますか?

4

2 に答える 2

1

「より良い」とは何ですか?

正規表現分割を使用してもう少し堅牢にすることもできますが、ソース CSV を制御できる場合は、ダーティ データについて心配する必要はありません。

私が目にする明らかな最適化の 1 つは、count() の結果をキャッシュすることです。

使用する:

for ($i = 1, $c=count($txtArray); $i < c - 1); $i++)

それ以外の:

for ($i = 1; $i < (count($txtArray) - 1); $i++ )

count() を呼び出すたびに、結果が再計算されます。計算は 1 回で十分なので、結果を保存するだけです。

なぜ必要なのかわかりません:

if (count($datArray) > 1)

「クリーン」なデータで作業している場合は、行ごとに一定数の値を持つ必要があるため、それら数えて何もチェックする必要はありません。高速化するために、ヘッダーの行数を数えて行の長さをキャッシュできます。

後:

$hdrArray = explode( "\t", $txtArray[0]);

行う:

$c2 = count($hdrArray);

次に、2 番目の for ループで使用します。

for($j = 0; $j < $c2; $j++)

空の行を心配する必要がある場合は、空の行を検索してループでスキップする方がおそらく高速です

このような:

// skip the row if the $datArray contains an empty array
if($datArray == array()) {
    continue;
}
$heads[$headerNames[$j]] = $datArray[$j];       

全体として、次のようになります。

$hdrArray = explode( "\t", $txtArray[0]);
$c2 = count($hdrArray);

// it has an iterator variable...
// I don't understand why you wouldn't use a for loop here
$i = 0;
foreach ($hdrArray as $hdr) {
    $heads[$hdr] = '';
    $headerNames[$i++] = $hdr;
}

for ($i = 1, $c = count($txtArray); $i < $c - 1; $i++) {
    $datArray = explode( "\t", $txtArray[$i]);
    for($j = 0; $j < $c2; $j++)
        // skip the row if the $datArray contains an empty array
        if($datArray == array()) {
            continue;
        }
        $heads[$headerNames[$j]] = $datArray[$j];
    }      
}

最初の実装が機能し、ソース データが実際には CSV であると仮定しています (つまり、固定数の行/列.

私が行ったのは、単純な (そして一般的な) 最適化をいくつか適用して、不要な計算の数を削減したことだけです。しばらくすると見慣れるかなり基本的なもの。

于 2012-04-27T08:23:06.647 に答える
1

入力ファイルが次のようになっていると仮定します。

head1 head2 head3
v11   v12   v13
v21   v22   v23
v31   v32   v33

それを解析するより簡単な方法は次のとおりです。

$hdrArray = explode("\t", $txtArray[0]); 
// array(3) { [0]=> string(5) "head1" [1]=> string(5) "head2" [2]=> string(6) "head3 " }

$length = count($txtArray) - 1; // having count in the for loop means it'll be executed at each iteration
$data   = array();

for($i = 1; $i <= $length; $i++) {
    $datArray = explode("\t", $txtArray[$i]); 
    // array(3) { [0]=> string(3) "v11" [1]=> string(3) "v12" [2]=> string(4) "v13 " }

    foreach($hdrArray as $key => $header) {
        $data[$i - 1][$header] = $datArray[$key]; // $i - 1 to start your $data array from 0
    }   
}

$data配列は次のようになります。

array(3) {
  [0]=>
  array(3) {
    ["head1"]=>
    string(3) "v11"
    ["head2"]=>
    string(3) "v12"
    ["head3"]=>
    string(4) "v13"
  }
  [1]=>
  array(3) {
    ["head1"]=>
    string(3) "v21"
    ["head2"]=>
    string(3) "v22"
    ["head3"]=>
    string(4) "v23"
  }
  [2]=>
  array(3) {
    ["head1"]=>
    string(3) "v31"
    ["head2"]=>
    string(3) "v32"
    ["head3"]=>
    string(3) "v33"
  }
}

count余分な反復を犠牲にして、完全にスキップできます。

foreach($txtArray as $i => $value) {
    if($i == 0) continue; // header, move on

    $datArray = explode("\t", $value); 

    foreach($hdrArray as $key => $header) {
        $data[$i - 1][$header] = $datArray[$key];
    }   
}

これは、最初の反復がすぐに停止し、ループが次の反復に続くため、count を使用するよりも実際には少し速いかもしれません。しかし、実際には配列のサイズに依存し、利益/損失はおそらく重要ではありません。

于 2012-04-27T08:26:03.913 に答える