0

値が配列であるハッシュがあります。これらの配列の共通要素を見つける必要があります。すべての配列に存在する要素。そこで、ハッシュの値を抽出して、各行がハッシュ内の配列に対応する多次元配列にしました。次に、このマトリックスの最初の行を別の配列 (@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;
}

上記が機能することは知っていますが、これを行う他の (perlish) 方法があるかどうかを知りたいです。私は perl を学び始めており、他の言語と比較して perl での作業がより簡単になる可能性があることを知りたいと思っています。私のコードが実行できる最高のものである場合は、それもお知らせください。任意のガイダンスをいただければ幸いです。ありがとう!

4

3 に答える 3

6

配列の交差を計算するための Chris Charley のリンクを見てください。

ハッシュは、このような問題を解決するための明確な方法です。と を組み合わせるmapgrep、ソリューションを数行に減らすことができます。

このプログラムは、より良いものを求めてサンダーのデータを使用しており、必要なことを行っているようです。

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

出力

A
C

編集

独自のソリューションのより 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;
}

出力は自分のプログラムと同じですが、各行の値が一意であると想定しているため、機能はわずかに異なります。sama 値が複数回表示される場合、私のソリューションは壊れます (同じことがsundarにも当てはまります)。それが受け入れられるかどうか教えてください。

于 2012-04-28T17:51:53.120 に答える
3

ポスターは、単一の配列内に重複がないことを説明しましたが、これもそのケースを処理する私の試みです(わずかに変更されたテストデータに注意してください-「5」は印刷されるべきではありません):

#!/usr/bin/env perl
use warnings;
use strict;

my %records = (
    a => [1, 2, 3],
    b => [3, 4, 5, 1],
    c => [1, 3, 5, 5]
);

my %seen;
while (my ($key, $vals) = each %records) {
    $seen{$_}{$key} = 1 for @$vals;
}

print "$_\n" for grep { keys %{$seen{$_}} == keys %records } keys %seen;
于 2012-04-29T01:17:32.557 に答える
1

を使用して簡単にハッシュのサイズを見つけることができますscalar(keys %hash);

必要なことを行うコード例を次に示します。

#!/usr/bin/perl

use strict;
use warnings;

my %records = ( a => [1, 2, 3],
                b => [3, 4, 5, 1],
                c => [1, 3, 5]
              );

my %count;
foreach my $arr_ref (values %records) {
    foreach my $elem (@$arr_ref) {
        $count{$elem}++;
    }
}

my @intersection;
my $num_arrays = scalar(keys %records);
foreach my $elem (keys %count) {
    #If all the arrays contained this element, 
    #allowing for multiple entries per array
    if ($count{$elem} >= $num_arrays) {
        push @intersection, $elem;
    }
}

このコードについて説明が必要な場合は、お気軽にコメントしてください。そして、@intersection 配列を構成する 2 番目の foreach は、わかりやすくするためにのみこのように記述されています。Perl を学習している場合は、map構成体を使用して学習し、書き直すことをお勧めします。

于 2012-04-28T16:42:56.407 に答える