سؤال

إذا حصلت على جدول في ملف نصي مثل

  • AB 1.
  • AC 2
  • 1 م
  • بكالوريوس 3.
  • CD 2
  • AE 1.
  • إد 2
  • CB 2
  • . . .
  • . . .
  • . . .

وحصلت على قائمة رمز أخرى في ملف نصي آخر. أريد تحويل هذا الجدول إلى بنية بيانات بيرل مثل:

  • _ ade. وبعد وبعد
  • 0 1 1. وبعد وبعد
  • د 1 0 2. وبعد وبعد
  • ه 1 2 0. وبعد وبعد
  • . . . . . . .

لكنني بحاجة فقط إلى بعض الرمز المحدد، على سبيل المثال، يتم تحديد 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.aw هو:

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

أنا لست فخورا جدا بخصوص الطريقة التي أعمل بها مراجع ولكنها تحمل مع مبتدئ هنا (يرجى ترك اقتراحاتك / التغييرات في التعليقات). تبدو طريقة التجزئة المذكورة أعلاه من قبل كريس أسهل بكثير (ناهيك عن الطباعة أقل بكثير).

CPAN. لديه الكثير من المحتمل أن تكون مفيدة. وبعد أنا أستعمل جدول البيانات لأغراض كثيرة. البيانات :: pivot. يبدو أيضا واعدة، لكنني لم أستخدمها أبدا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top