Question

Si je suis une table dans un fichier texte tel que

  • A B 1
  • A C 2
  • A D 1
  • B A 3
  • C D 2
  • A E 1
  • E D 2
  • C B 2
  • . . .
  • . . .
  • . . .

Je suis une autre liste de symboles dans un autre fichier texte. Je veux transformer ce tableau dans une structure de données Perl comme:

  • _ A D E. . .
  • A 0 1 1. . .
  • D 1 0 2. . .
  • E 1 2 0. . .
  • . . . . . . .

Mais je ne ai besoin un symbole choisi, par exemple A, D et E sont sélectionnés dans le texte de symbole, mais B et C ne sont pas.

Était-ce utile?

La solution

utiliser un tableau pour la première et une table de hachage 2-dimensionnel pour la seconde. Le premier devrait ressembler à peu près comme:

$list[0] # row 1 - the value is "A B 1"

Et le hachage comme:

$hash{A}{A} # the intersection of A and A - the value is 0

Comprendre comment mettre en œuvre un problème est d'environ 75% de la bataille mentale pour moi. Je ne vais pas entrer dans les détails sur la façon d'imprimer le hachage ou le tableau, car c'est facile et je ne suis pas non plus tout à fait clair sur la façon dont vous voulez imprimer ou combien vous voulez imprimer. Mais la conversion du tableau à la table de hachage devrait ressembler un peu comme ceci:

foreach (@list) {
  my ($letter1, $letter2, $value) = split(/ /);
  $hash{$letter1}{$letter2} = $value;
}

Au moins, je pense que c'est ce que vous cherchez. Si vous vraiment voulez, vous pouvez utiliser une expression régulière, mais est probablement trop pour juste extraire 3 valeurs sur une chaîne.

EDIT: Bien sûr, vous pouvez renoncer à la @list et il suffit d'assembler le hachage directement à partir du fichier. Mais c'est votre travail pour comprendre, pas le mien.

Autres conseils

vous pouvez essayer avec awk:

awk -f matrix.awk yourfile.txt> newfile.matrix.txt

où matrix.awk est:

BEGIN {
   OFS="\t"
}
{
  row[$1,$2]=$3
  if (!($2 in f2)) { header=(header)?header OFS $2:$2;f2[$2]}
  if (col1[c]!=$1)
     col1[++c]=$1
}
END {
  printf("%*s%s\n", length(col1[1])+2, " ",header)
  ncol=split(header,colA,OFS)
  for(i=1;i<=c;i++) {
    printf("%s", col1[i])
    for(j=1;j<=ncol;j++)
      printf("%s%s%c", OFS, row[col1[i],colA[j]], (j==ncol)?ORS:"")
  }
}

Une autre façon de le faire serait de faire un tableau à deux dimensions -

my @fArray = ();
## Set the 0,0th element to "_"
push @{$fArray[0]}, '_';

## Assuming that the first line is the range of characters to skip, e.g. BC
chomp(my $skipExpr = <>);

while(<>) {
    my ($xVar, $yVar, $val) = split;

    ## Skip this line if expression matches
    next if (/$skipExpr/);

    ## Check if these elements have already been added in your array
    checkExists($xVar);
    checkExists($yVar);

    ## Find their position 
    for my $i (1..$#fArray) {
        $xPos = $i if ($fArray[0][$i] eq $xVar);
        $yPos = $i if ($fArray[0][$i] eq $yVar);
    }

    ## Set the value 
    $fArray[$xPos][$yPos] = $fArray[$yPos][$xPos] = $val;
}

## Print array
for my $i (0..$#fArray) {
    for my $j (0..$#{$fArray[$i]}) {
        print "$fArray[$i][$j]", " ";
    }
    print "\n";
}

sub checkExists {
    ## Checks if the corresponding array element exists,
    ## else creates and initialises it.
    my $nElem = shift;
    my $found;

    $found = ($_ eq $nElem ? 1 : 0) for ( @{fArray[0]} );

    if( $found == 0 ) {
        ## Create its corresponding column
        push @{fArray[0]}, $nElem;

        ## and row entry.
        push @fArray, [$nElem];

        ## Get its array index
        my $newIndex = $#fArray;

        ## Initialise its corresponding column and rows with '_'
        ## this is done to enable easy output when printing the array
        for my $i (1..$#fArray) {
            $fArray[$newIndex][$i] = $fArray[$i][$newIndex] = '_';
        }

        ## Set the intersection cell value to 0
        $fArray[$newIndex][$newIndex] = 0;
    }
}

Je ne suis pas trop fier en ce qui concerne la façon dont je me suis occupé des références, mais supporter un débutant ici (s'il vous plaît laisser vos suggestions / changements dans les commentaires). La méthode de hachage ci-dessus mentionné par Chris semble beaucoup plus facile (sans parler de beaucoup moins de frappe).

CPAN a beaucoup potentiellement utile suff. J'utilise Tableau de données à de nombreuses fins. données :: Pivot semble également prometteuse, mais je ne l'ai jamais utilisé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top