Frage

Wenn habe ich eine Tabelle in einer Textdatei so wie

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

Und ich habe eine andere Symbolliste in einer anderen Textdatei. Ich möchte diese Tabelle in eine Struktur Perl Daten zu transformieren, wie:

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

Aber ich nur einige ausgewählten Symbole benötigen, beispielsweise A, D und E sind in dem Symbol Text ausgewählt, aber B und C nicht.

War es hilfreich?

Lösung

ein Array für die ersten und einen 2-dimensionalen Hash für die zweiten. Die erste sollte in etwa wie folgt aussehen:

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

Und die Hash wie:

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

Herauszufinden, wie zu implementieren, um ein Problem etwa 75% des mentalen Kampfes für mich. Ich werde hier nicht auf Einzelheiten darüber, wie die Hash oder das Array zu drucken, denn das ist einfach und ich bin auch nicht ganz klar, wie Sie es wollen gedruckt oder wie viel Sie gedruckt. Aber Umwandlung des Array an den Hash sollte ein bisschen wie folgt aussehen:

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

Zumindest denke ich, dass das, was Sie suchen. Wenn Sie wirklich wollen Sie einen regulären Ausdruck verwenden könnten, aber das ist wahrscheinlich übertrieben für nur Extrahieren 3 Werte aus einer Zeichenkette.

EDIT: Natürlich könnte man die @list verzichten und nur den Hash direkt aus der Datei zusammenstellen. Aber das ist Ihre Aufgabe, um herauszufinden, nicht meine.

Andere Tipps

Sie können versuchen, diese mit awk:

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

wo matrix.awk ist:

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:"")
  }
}

Eine andere Möglichkeit, dies zu tun wäre, um eine zweidimensionale Anordnung zu machen -

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;
    }
}

Ich bin nicht zu stolz, in Bezug auf die Art, wie ich Referenzen behandelt haben, aber tragen mit einem Anfänger hier (bitte Ihre Anregungen / Änderungen in den Kommentaren hinterlassen). Das oben genannte Hash-Verfahren von Chris klingt viel einfacher (nicht viel weniger tippen zu erwähnen).

CPAN hat viele potenziell nützlicher ausr . Ich benutze Data :: Tabelle für viele Zwecke. Data :: Pivot sieht auch vielversprechend aus, aber ich habe es nie benutzt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top