Perl 如何将表格转换为矩阵?
如果我在这样的文本文件中有一个表Perl 如何将表格转换为矩阵?,perl,hash,matrix,perl-data-structures,Perl,Hash,Matrix,Perl Data Structures,如果我在这样的文本文件中有一个表 A B 1 A C 2 A D 1 B A 3 C D 2 A E 1 E D 2 C B 2 我在另一个文本文件中得到了另一个符号列表。我想将此表转换为Perl数据结构,如: _A D E 一个0 1 1 D 1 0 2 E120 但我只需要一些选定的符号,例如,符号文本中选择了A、D和E,但B和C没有选择。第一个符号使用数组,第二个符号使用二维哈希。第一个应该大致如下所示: $list[0] # row 1 - the value is "A
- A B 1
- A C 2
- A D 1
- B A 3
- C D 2
- A E 1
- E D 2
- C B 2
- 李>
- 李>
- 李>
- _A D E李>
- 一个0 1 1李>
- D 1 0 2李>
- E120李>
- 李>
但我只需要一些选定的符号,例如,符号文本中选择了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;
}
至少,我认为这就是你想要的。如果确实需要,可以使用正则表达式,但仅从字符串中提取3个值可能有些过分
编辑:当然,您可以放弃
@list
,直接从文件中组装哈希。但这是你的工作,不是我的。另一种方法是制作一个二维数组-
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;
}
}
my@fArray=();
##将第0,0个元素设置为“\u0”
推送{$fArray[0]},';
##假设第一行是要跳过的字符范围,例如BC
chomp(我的$skipExpr=);
while(){
我的($xVar,$yVar,$val)=分割;
##如果表达式匹配,则跳过此行
下一个if(/$skipExpr/);
##检查这些元素是否已添加到数组中
支票存在($xVar);
支票存在($yVar);
##找到他们的位置
为了我的$i(1..$#fArray){
$xPos=$i if($fArray[0][$i]eq$xVar);
$yPos=$i if($fArray[0][$i]eq$yVar);
}
##设置值
$fArray[$xPos][$yPos]=$fArray[$yPos][$xPos]=$val;
}
##打印阵列
对于我的$i(0..$#fArray){
对于我的$j(0..$#{$fArray[$i]}){
打印“$fArray[$i][$j]”,“”;
}
打印“\n”;
}
子支票存在{
##检查对应的数组元素是否存在,
##else创建并初始化它。
我的$nElem=班次;
我的美元找到了;
$found=(${fArray[0]})的($eq$nElem?1:0);
如果($found==0){
##创建相应的列
推{fArray[0]},$nElem;
##和行输入。
推@fArray,[$nElem];
##获取其数组索引
我的$newIndex=$#fArray;
##用“\”初始化其相应的列和行
##这样做是为了在打印阵列时方便输出
为了我的$i(1..$#fArray){
$fArray[$newIndex][$i]=$fArray[$i][$newIndex]='';
}
##将相交单元值设置为0
$fArray[$newIndex][$newIndex]=0;
}
}
对于我处理推荐信的方式,我不太自豪,但请容忍这里的初学者(请在评论中留下您的建议/更改)。上面提到的Chris的hash方法听起来简单得多(更不用说打字量少了)。有很多。我使用它有很多用途。看起来也很有希望,但我从未使用过它。您可以用awk试试: awk-f matrix.awk yourfile.txt>newfile.matrix.txt 其中matrix.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:"")
}
}
开始{
OFS=“\t”
}
{
行[$1,$2]=$3
如果(!(f2中的$2)){header=(header)?S$2的头:$2;f2[$2]}
如果(col1[c]!=1美元)
col1[++c]=1美元
}
结束{
printf(“%*s%s\n”,长度(col1[1])+2,”,标题)
ncol=拆分(收割台、可乐、OFS)
对于(i=1;i)你的问题对我来说很不清楚。你能重新解释一下吗?如果散列键足够简单,你可以使用一个散列来连接键。所以$hash{AD}保持1。如果使用得当,此方法可以简化代码。如果使用不当,会导致出现奇怪的错误和难看的代码。此技术应仅用于非常简单的哈希键。我尝试使用哈希,但在打印值时出现一些问题。我的代码发布在下面(回答4)。请看一看。谢谢!-Debbie如果我将所有必需的字符保存到数组@all_node中。我可以将“next if(/$skipExpr/);”更改为“next除非(/@all_node/);”?数组@all_node将在列表分隔符变量的帮助下进行插值-$默认情况下,它设置为一个空格“”。因此它可以工作,但在正则表达式中使用数组之前需要将其设置为“”。local$“=”;next,除非(/@all_node/);