테이블을 매트릭스로 어떻게 바꾸나요?
-
22-08-2019 - |
문제
텍스트 파일에 테이블이있는 경우
- AB 1
- AC 2
- AD 1
- BA 3
- CD 2
- ae 1
- 에드 2
- CB 2
- . . .
- . . .
- . . .
다른 텍스트 파일에 다른 기호 목록이 있습니다. 이 테이블을 다음과 같은 PERL 데이터 구조로 변환하고 싶습니다.
- _ ade. . .
- A 0 1 1. . .
- D 1 0 2. . .
- E 1 2 0. . .
- . . . . . . .
그러나 선택한 기호 만 필요합니다 (예 : a, d 및 e는 기호 텍스트에서 선택되지만 b와 c는 그렇지 않습니다.
해결책
첫 번째 배열에는 배열을 사용하고 두 번째는 2 차원 해시를 사용하십시오. 첫 번째는 대략적인 모습을 보여야합니다.
$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
파일에서 해시를 바로 조립하십시오. 그러나 그것은 내 것이 아니라 당신의 일입니다.
다른 팁
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:"")
}
}
이렇게하는 또 다른 방법은 2 차원 배열을 만드는 것입니다.
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;
}
}
나는 참고 문헌을 처리 한 방식에 대해 너무 자랑스럽지 않지만 여기에 초보자와 함께 견딜 수 있습니다 (귀하의 제안/변경 사항을 의견에 남겨주세요). Chris의 위에서 언급 한 해시 방법은 훨씬 쉽게 들립니다 (타이핑이 훨씬 적은 것은 말할 것도 없습니다).
CPAN 많이있다 잠재적으로 유용한 Suff. 나는 사용한다 데이터 :: 테이블 많은 목적을 위해. 데이터 :: 피벗 또한 유망 해 보이지만 나는 그것을 사용한 적이 없습니다.