Perl - Hash of hash and columns :(

5

我有一组变量大小的字符串,例如:

AAA23

AB1D1

A1BC

AAB212

我的目标是按字母顺序收集唯一字符的列,例如:

第一列:AAAA

第二列:AB1A

以此类推...

目前,我可以通过哈希表提取帖子。但是现在,如何对数据进行排序?我能为每个哈希表创建一个新数组吗?

非常感谢您的帮助!

Al

我的代码:

#!/usr/bin/perl

use strict;
use warnings;

my @sessions = (
    "AAAA",
    "AAAC",
    "ABAB",
    "ABAD"
);

my $length_max = 0;
my $length_tmp = 0;

my %columns;

foreach my $string (@sessions){

    my $l = length($string);

    if ($l > $length_tmp){
            $length_max = $l;
    }
}

print "max legth : $length_max\n\n";

my $n = 1;

foreach my $string (@sessions){

    my @ch = split("",$string);

    for my $col (1..$length_max){
        $columns{$n}{$col} = $ch[$col-1];
    }

    $n++;
}

foreach my $col (keys %columns) {

    print "colonna : $col\n";

    my $deref = $columns{$col};

    foreach my $pos (keys %$deref){
            print " posizione : $pos --> $$deref{$pos}\n";
    }

    print "\n";
}

exit(0);

在第五和第六列中,一些字符缺失,你打算怎么做? - Zaid
你说你想要每列都有唯一的字符。对于一个具有一些数学训练的英语母语者来说,这意味着每列都不应该包含重复的字符,但是你给出的第一列和第二列的预期答案分别是AAAAAB1A。数字应该如何与字母字符排序?考虑到A出现在第二列答案的开头和结尾,它似乎根本没有排序。 - Greg Bacon
2个回答

2
你正在做的是旋转数组。它不需要哈希或其他任何东西,只需要另一个数组。令人惊讶的是,List::Util和List::MoreUtils都没有提供这样的功能。这里有一个简单的实现和一个测试。我假设你想用空格填充短条目,以便列正确对齐。
#!/usr/bin/perl

use strict;
use warnings;

use Test::More;
use List::Util qw(max);

my @Things = qw(
    AAA23
    AB1D1
    A1BC
    AAB212
);


sub rotate {
    my @rows = @_;

    my $maxlength = max map { length $_ } @rows;

    my @columns;
    for my $row (@rows) {
        my @chars = split //, $row;
        for my $colnum (1..$maxlength) {
            my $idx = $colnum - 1;
            $columns[$idx] .= $chars[$idx] || ' ';
        }
    }

    return @columns;
}


sub print_columns {
    my @columns = @_;

    for my $idx (0..$#columns) {
        printf "Column %d: %s\n", $idx + 1, $columns[$idx];
    }
}


sub test_rotate {
    is_deeply [rotate @_], [
        "AAAA",
        "AB1A",
        "A1BB",
        "2DC2",
        "31 1",
        "   2",
    ];
}


test_rotate(@Things);
print_columns(@Things);
done_testing;

每次看到关于数组旋转的文章,我就会想到 Raymond Chen 写的这篇博客:http://blogs.msdn.com/b/oldnewthing/archive/2008/09/02/8918130.aspx。在读完正文之后,往下滑动到“640k”发表的评论区,那里有一些有趣的内容。“你甚至可以将其旋转10度!” - Justin R.
1
是的,当我在List::MoreUtils中没有找到transpose时,我也感到失望... - Zaid

0
您可以使用以下代码对%columns的输出进行排序:
foreach my $i (sort { $a <=> $b } keys %columns) {
  print join(" " => sort values %{ $columns{$i} }), "\n";
}

这会得到

A A A A 
A A A C 
A A B B 
A A B D

但是使用索引号作为哈希键非常不合适,应该使用数组代替,所以让我们这样做。要获取列,请使用

sub columns {
  my @strings = @_;
  my @columns;

  while (@strings) {
    push @columns => [ sort map s/^(.)//s ? $1 : (), @strings ];
    @strings = grep length, @strings;
  }

  @columns;
}

根据您的问题中的字符串,它返回

A A A A
1 A A B
1 A B B
2 2 C D
1 1 3
2

正如您所看到的,这是未排序的并且字符重复。使用Perl时,当您看到单词“unique”时,请始终考虑哈希表!

sub unique_sorted_columns {
  map { my %unique;
        ++$unique{$_} for @$_;
        [ sort keys %unique ];
      }
      columns @_;
}

如果您不介意破坏信息,您可以使用columns对重复项进行排序和过滤:

sub columns {
  my @strings = @_;
  my @columns;

  while (@strings) {
    my %unique;
    map { ++$unique{$1} if s/^(.)//s } @strings;
    push @columns => [ sort keys %unique ];
    @strings = grep length, @strings;
  }

  @columns;
}

输出:

A
1 A B
1 A B
2 C D
1 3
2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接