這真是一個有趣的問題。我會用Perl來回答。
我們需要一次讀取同一範圍內的所有行。這些範圍內的每個數字還必須記住它們來自哪條線。然後,我們可以對每個範圍的數字進行排序,然後重新組裝線條。
對於第一個範圍,我們將有值的集合像
[213 => 1], [253 => 1], [295 => 1], [350 => 1],
[260 => 2], [295 => 2], [315 => 2],
[205 => 3], [263 => 3], [295 => 3],
我們應該去重複的公共數字,使我們得到
[213 => 1], [253 => 1], [295 => 1, 2, 3], [350 => 1],
[260 => 2], [315 => 2],
[205 => 3], [263 => 3],
(順序並不重要)。
:
my @sorted = sort { $a->[0] <=> $b->[0] } @items;
對於每一行,那麼我們就可以通過排序項目迭代,並通過行號決定,如果我們打印NA
或多項:
我們可以把這些項目通過的第一個字段排序
for my $line (1 .. 3) {
my @fields = map { decide_if_number_or_na($line, @$_) } @sorted;
...
}
sub decide_if_number_or_na {
my ($line, $number, @lines) = @_;
return $number if grep { $line == $_ } @lines; # ... if any of the lines is our line
return "NA";
}
當然,我們應該立即發出正確的0
或1
值。
將所有這一切聯繫起來有點複雜。在解析輸入的過程中,我們需要將每行與當前的01
模式相關聯,記住前兩個字段,併爲這些項目構建數據結構。
產生的代碼遵循上述考慮,但需要一些快捷方式:一旦訂購了它們,每個數字的實際值對我們的物品並不重要,我們可以放棄它。
use strict; use warnings; use feature 'say';
my @lines; # an array of hashes, which hold information about each line
my %ranges; # a hash mapping range identifiers to number-to-occuring-line-array hashes
while (<>) {
chomp;
my ($letter, $range, @nums) = split; # split everything into field ...
my @pattern = split //, pop @nums; # but the last field is a pattern, which we split into chars.
push @{ $ranges{$range}{$_} }, $. for @nums; # $. is the line no
push @lines, {
letter => $letter,
range => $range,
pattern => \@pattern,
line => $.,
};
}
# simplify and sort the ranges:
for my $key (keys %ranges) {
my $nums2lines = $ranges{$key}; # get the number-to-occuring-lines-array hashes
# read the next statement bottom to top:
my @items =
map { $nums2lines->{$_} } # 3. get the line number arrayref only (forget actual number, now that they are ordered)
sort { $a <=> $b } # 2. sort them numerically
keys %$nums2lines; # 1. get all numbers
$ranges{$key} = \@items; # Remember these items at the prior position
}
# Iterate through all lines
for my $line (@lines) {
# Unpack some variables
my @pattern = @{ $line->{pattern} };
my $lineno = $line->{line};
my $items = $ranges{$line->{range}};
# For each item, emit the next part of the pattern, or NA.
my @fields = map { pattern_or_na($lineno, @$_) ? shift @pattern : "NA" } @$items;
say join "\t", $line->{letter}, $line->{range}, @fields;
}
sub pattern_or_na {
my ($line, @lines) = @_; # the second value (the specific number)
return scalar grep { $_ == $line } @lines; # returns true if a number is on this line
}
它產生所需的輸出。
這是相當複雜的代碼,特別是對於初學者。它使用Perl參考和autovivifiction。此外,我使用許多列表變換,如sort
,map
或grep
。該解決方案沒有考慮到具有相同範圍的行是連續的,所以我不必將所有內容都保存在內存中。這個解決方案比較簡單(特殊!),但是使用的內存比需求更多。
我建議您閱讀perlreftut
,perlre
和perldsc
手冊,以瞭解所有這些內容。
你有什麼試過?請注意,你發佈了一個相關的問題http://stackoverflow.com/questions/18273941/compare-rows-and-print-the-same-values-for-the-same-rows,你可以重新使用一些代碼。 – fedorqui
任何人都有魔杖? – devnull
你在這裏填充新生感覺如何?並請更正您的標題中的錯字。 – Arun