Как превратить таблицу в матрицу?
-
22-08-2019 - |
Вопрос
Если бы я получил таблицу в текстовом файле, например
- А Б 1
- А С 2
- А Д 1
- Б А 3
- К Д 2
- А Е 1
- Э Д 2
- С Б 2
- . . .
- . . .
- . . .
И я получил еще один список символов в другом текстовом файле.Я хочу преобразовать эту таблицу в структуру данных Perl, например:
- _ А Д Е ...
- А 0 1 1 ...
- Д 1 0 2 ...
- Е 1 2 0 ...
- . . . . . . .
Но мне нужен только какой-то выбранный символ, например, в тексте символа выбраны A, D и E, а B и C — нет.
Решение
Используйте массив для первого и двумерный хэш для второго.Первый из них должен выглядеть примерно так:
$list[0] # row 1 - the value is "A B 1"
И хеш типа:
$hash{A}{A} # the intersection of A and A - the value is 0
Понимание того, как решить задачу, составляет для меня около 75% умственной битвы.Я не буду вдаваться в подробности о том, как распечатать хеш или массив, потому что это просто, и я также не совсем понимаю, как вы хотите его напечатать или сколько вы хотите напечатать.Но преобразование массива в хеш должно выглядеть примерно так:
foreach (@list) {
my ($letter1, $letter2, $value) = split(/ /);
$hash{$letter1}{$letter2} = $value;
}
По крайней мере, я думаю, что это то, что вы ищете.Если вы Действительно Я хочу, чтобы вы могли использовать регулярное выражение, но это, вероятно, излишне для извлечения трех значений из строки.
РЕДАКТИРОВАТЬ:Конечно, вы могли бы отказаться от @list
и просто соберите хеш прямо из файла.Но это ваша работа, а не моя.
Другие советы
вы можете попробовать это с помощью awk:
awk -f матрица.awk вашфайл.txt > новыйфайл.matrix.txt
где матрица.awk:
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:"")
}
}
Другой способ сделать это — создать двумерный массив:
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;
}
}
Я не слишком горжусь тем, как я обрабатываю ссылки, но терплю здесь новичка (пожалуйста, оставляйте свои предложения/изменения в комментариях).Вышеупомянутый метод хеширования Криса звучит намного проще (не говоря уже о том, что требуется гораздо меньше ввода).
КПАН имеет много потенциально полезный материал.я использую Таблица данных для многих целей. Данные::Пивот тоже выглядит многообещающе, но я никогда им не пользовался.