4

漠然とした質問で申し訳ありませんが、私はそれをより適切に表現する方法を考えるのに苦労しています!

私はこのような少しだけ大きいCSVファイルを持っています:

550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4

最初の列の値はID番号であり、2番目の列はプロパティとして記述できます(より適切な単語が必要な場合...)。ID番号550672には、プロパティ1、2、3、4があります。すべてのID番号のような文字列を作成する方法を解決する方法を誰かに教えてもらえますか?私の理想的な出力は、次のような新しいcsvファイルです。

550672,1;2;3;4
656372,1;2
766153,1;4

私はPerlの赤ちゃん(生後わずか3日です!)なので、完全な解決策ではなく、方向性を本当に感謝します。残りの日数がかかる場合でも、このことを学ぶことにします。私は自分でできる限り調査しようとしましたが、実際に何を検索すればよいかわからないことに悩まされてきたと思います。CSVファイルを読み込んで解析することはできますが(重複する値を削除することもできます!)、それが私にとっては本当に重要なことです。どんな助けでも大歓迎です!

4

5 に答える 5

4

いくつかのヒントではなく、実際に動作するプログラムを提供するのが最善だと思います。ヒントはここまでしか説明できません。時間をかけてこのコードを理解すれば、良い学習体験が得られます。

Text::CSVすべてのデバッグが既に行われているため、CSV データを処理するときはいつでも使用するのが最適です。

use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV->new;

open my $fh, '<', 'data.txt' or die $!;
my %data;
while (my $line = <$fh>) {
  $csv->parse($line) or die "Invalid data line";
  my ($key, $val) = $csv->fields;
  push @{ $data{$key} }, $val
}

for my $id (sort keys %data) {
  printf "%s,%s\n", $id, join ';', @{ $data{$id} };
}

出力

550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
于 2012-09-16T23:37:41.010 に答える
3

まず、解決策ではなくアプローチを求めるための小道具。おそらくすでに perl で見つけたように、それを行う方法は複数あります。

私がとるアプローチは次のとおりです。

use strict;  # will save you big time in the long run

my %ids      # Use a hash table with the id as the key to accumulate the properties
open a file handle on csv or die
while (read another line from the file handle){
  split line into ID and property variable  # google the split function
  append new property to existing properties for this id in the hash table  # If it doesn't exist already, it will be created
}

foreach my $key (keys %ids) {
  deduplicate properties
  print/display/do whatever you need to do with the result
}

このアプローチは、セット全体を 2 回 (メモリ内で 1 回) 反復する必要があることを意味するため、データセットのサイズによっては問題になる可能性があります。より洗練されたアプローチは、最初のステップでハッシュテーブルのハッシュテーブルを使用して重複排除を行うことですが、それを機能させるために必要な/必要な速度によっては、最初のインスタンスでは価値がない場合があります。

重複排除の方法については、この質問を参照してください 。

于 2012-09-16T22:04:05.147 に答える
2

さて、perlでstdinとしてファイルを開き、各行が2列であると想定し、左の列をハッシュ識別子として使用してすべての行を反復し、右の列をハッシュキーが指す配列に収集します。入力ファイルの最後に配列のハッシュが表示されるので、それを繰り返し処理して、ハッシュキーと割り当てられた配列要素を「;」で区切って出力します。またはあなたが望む他のサイン。

そしてここに行きます

dtpwmbp:~ pwadas$ cat input.txt 
550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4
dtpwmbp:~ pwadas$ cat bb2.pl 
#!/opt/local/bin/perl

my %hash;
while (<>)
{
    chomp;
    my($key, $value) = split /,/;
    push @{$hash{$key}} , $value ;
}

foreach my $key (sort keys %hash)
{
     print $key . "," . join(";", @{$hash{$key}} ) . "\n" ;
}
dtpwmbp:~ pwadas$ cat input.txt | perl -f bb2.pl 
550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
dtpwmbp:~ pwadas$
于 2012-09-16T21:47:05.693 に答える
2
perl -F"," -ane 'chomp($F[1]);$X{$F[0]}=$X{$F[0]}.";".$F[1];if(eof){for(keys %X){$X{$_}=~s/;//;print $_.",".$X{$_}."\n"}}'
于 2012-09-17T09:56:50.800 に答える
1

ちなみに、より短くてエレガントな別の(perlではない)方法:

#!/opt/local/bin/gawk -f

BEGIN {FS=OFS=",";}

NF > 0 { IDs[$1]=IDs[$1] ";" $2; }

END { for (i in IDs) print i, substr(IDs[i], 2); }

最初の行 (インタープリターを指定した後) では、入力 FIELD SEPARATOR と OUTPUT FIELD SEPARATOR をコンマに設定します。2 行目は、フィールドが 0 個以上あることを確認し、そうである場合は ID ($1) 番号をキーに、$2 を値にします。これをすべての行に対して行います。

END ステートメントは、これらのペアを不特定の順序で出力します。それらを並べ替えたい場合は、asortignu awk 関数のオプションを選択するか、このスニペットの出力をパイプで に接続する必要がありますsort -t, -k1n,1n

于 2012-09-16T23:13:09.953 に答える