查找数组中的常见元素

use*_*647 0 arrays perl

我有一个散列,其值是数组.我需要找到那些数组的共同元素,即.所有数组中都存在的元素.所以我将哈希值提取到一个多维数组中,每个数组对应于哈希中的一个数组.然后我将这个矩阵的第一行放到另一个数组(@ arr1)中并迭代它以查找arr1中是否还有任何元素也在矩阵的其余行中.如果找到这样的元素,则将其推送到包含所有元素的最终列表的另一个数组.代码如下(我希望它足够清楚):

sub construct_arr(my %records) {
    my $len = keys %records;
    my @matrix;
    my $i = 0;

    # Extract the values of the hash into a matrix
    foreach my $key (keys %records) {
        $matrix[$i] = $records{$key};
        $i++;   
    }

    my @arr1 = $matrix[0];
    my @final;

    # Iterate through each element of arr1
    for my $j (0..$#{$arr1[0]}) {
        my $count = 1;

        # Iterate through each row of the matrix, starting from the second
        for ( my $i = 1; $i < $len ; $i++ ) {
            my $flag = 0;

            # Iterate through each element of the row
            for my $k (0..$#{$matrix[$i]}) {
                if ($arr1[0][$j] eq $matrix[$i][$k]) {
                    $flag = 1;
                    $count++;
                }
            }

            # On finding the first instance of the element in a row, go to the next row
            if (!$flag == 1) {
                last;
            }       
        }

        # If element is in all the rows, push it on to the final array
        if ($count == $len) {
            push(@final, $arr1[0][$j]);
        }
    }
    return @final;
}
Run Code Online (Sandbox Code Playgroud)

我知道上面的工作,但我想知道是否有任何其他(perlish)方式来做到这一点.我开始学习perl,我非常有兴趣了解可以使我的工作在perl中比其他语言更容易的事情.如果我的代码是最好的,请告诉我.任何指导将不胜感激.谢谢!

Bor*_*din 6

看看Chris Charley用于计算数组交集链接.

哈希是解决这类问题的明确方法.加上mapgrep解决方案可以减少到只有几行.

该程序使用sundar的数据来获得更好的东西,并且似乎可以满足您的需求.

use strict;
use warnings;

my %records = (
  a => [ qw/ A B C / ],
  b => [ qw/ C D E A / ],
  c => [ qw/ A C E / ],
);

print "$_\n" for construct_arr(\%records);

sub construct_arr {
  my $records = shift;
  my %seen;
  $seen{$_}++ for map @$_, values %$records;
  grep $seen{$_} == keys %$records, keys %seen;
}
Run Code Online (Sandbox Code Playgroud)

产量

A
C
Run Code Online (Sandbox Code Playgroud)

编辑

我认为看到更多Perlish,整理自己的解决方案可能会有所帮助.

use strict;
use warnings;

my %records = (
  a => [ qw/ A B C / ],
  b => [ qw/ C D E A / ],
  c => [ qw/ A C E / ],
);

print "$_\n" for construct_arr(\%records);

sub construct_arr {

  my $records = shift;
  my @matrix = values %$records;
  my @final;

  # iterate through each element the first row
  for my $i ( 0 .. $#{$matrix[0]} ) {

    my $count = 1;

    # look for this value in all the rest of the rows, dropping
    # out to the next row as soon as a match is found
    ROW:
    for my $j ( 1 .. $#matrix ) {
      for my $k (0 .. $#{$matrix[$j]}) {
        next unless $matrix[0][$i] eq $matrix[$j][$k];
        $count++;
        next ROW;
      }
    }

    # If element is in all the rows, push it on to the final array
    push @final, $matrix[0][$i] if $count == @matrix;
  }

  return @final;
}
Run Code Online (Sandbox Code Playgroud)

输出与我自己的程序相同,但功能略有不同,因为我假设每行中的值是唯一的.如果sama值出现不止一次,我的解决方案将会中断(同样适用于sundar's).如果可以接受,请告诉我.