Динамически / рекурсивно строит хеши в Perl? - PullRequest
8 голосов
/ 30 декабря 2010

Я довольно новичок в Perl и пытаюсь рекурсивно создать хеш и ничего не получится.Я пытался найти учебники для динамического построения хэшей, но все, что я мог найти, это вводные статьи о хэшах.Буду признателен, если вы укажете мне правильное направление или предложите хорошую статью / учебник.

Я пытаюсь прочитать из файла, который имеет пути в виде

one/two/three
four
five/six/seven/eight

, и я хочу создать хеш, например

VAR = {
    one : {
        two : {
            three : ""
        }
    }
    four : ""
    five : {
        six : {
            seven : {
                 eight : ""
            }
        }
    }
}

СценарийЯ использую в настоящее время:

my $finalhash = {}; 
my @input = <>;

sub constructHash {
    my ($hashrf, $line) = @_; 
    @elements = split(/\//, $line);
    if(@elements > 1) {
        $hashrf->{shift @elements} = constructHash($hashrf->{$elements[0]}, @elements ); 
    } else {
        $hashrf->{shift @elements} = ""; 
    }
    return $hashrf;
}

foreach $lines (@input) {
    $finalhash = constructHash($finalhash, $lines);
}

Ответы [ 5 ]

7 голосов
/ 30 декабря 2010

Data::Diver охватывает эту нишу так хорошо, что люди не должны изобретать велосипед.

use strict;
use warnings;
use Data::Diver 'DiveVal';
use Data::Dumper;

my $root = {};
while ( my $line = <DATA> ) {
    chomp($line);
    DiveVal( $root, split m!/!, $line ) = '';
}
print Dumper $root;
__DATA__
one/two/three
four
five/six/seven/eight
6 голосов
/ 30 декабря 2010

Это немного надумано, но работает:

sub insert {
  my ($ref, $head, @tail) = @_;
  if ( @tail ) { insert( \%{$ref->{$head}}, @tail ) }
  else         {            $ref->{$head} = ''      }
}

my %hash;
chomp and insert \%hash, split( '/', $_ ) while <>;

Он основан на автовивификации, которая, по общему признанию, немного продвинута для новичка.

Что, вероятно, сделает любой ответ на ваш вопрос несколько искаженным, так это то, что вы запрашиваете пустые строки в листьях, который имеет «тип», отличный от хэшей узлов, и требует другой операции разыменования.

4 голосов
/ 30 декабря 2010

Я никогда не делал что-то подобное, так что такой подход, скорее всего, будет неправильным, но хорошо, вот мой шанс:

use 5.013;
use warnings;
use Data::Dumper;

sub construct {
   my $hash = shift;
   return unless @_;

   return construct($hash->{shift()} //= {}, @_);
}

my %hash;

while (<DATA>) {
   chomp;
   construct(\%hash, split m!/!);
}

say Dumper \%hash;

__DATA__
one/two/three
four
five/six/seven/eight

РЕДАКТИРОВАТЬ: Исправлено!

РЕДАКТИРОВАТЬ 2: (я думаю) версия, оптимизированная для хвостового вызова, потому что!

sub construct {
   my $hash = shift;
   return unless @_;
   unshift @_, $hash->{shift()} //=  @_ ? {} : '';

   goto &construct;
}
3 голосов
/ 30 декабря 2010

Я запустил ваш код и обнаружил несколько проблем:

  • вы не правильно охватили @elements.
  • с этой рекурсией вы создаете хеш, который ссылается на себя, не , что вы хотите.
  • в вашем самом внешнем вызове, второй аргумент constructHash() - это строка, но при рекурсивном вызове внутри вы передаете массив @elements

Попробуйте это.

use Data::Dumper;

my $finalhash = {}; 
my @input = split "\n", <<INPUT;
one/two/three
four
five/six/seven/eight
INPUT

sub constructHash {
    my $line = shift; 
    my ($first, $remainder) = split(/\//, $line,2);

    if ($remainder) {
        return { $first => constructHash($remainder) } ; 
    } else {
        return { $first , "" }; 
    }
}

foreach $lines (@input) {
    my $linehash = constructHash($lines);
    my $firstkey = (keys %$linehash)[0];
#    print Dumper $linehash;
    $finalhash->{$firstkey} = $linehash->{$firstkey};
} 


print Dumper $finalhash;

Производит

$VAR1 = {
          'five' => {
                      'six' => {
                                 'seven' => {
                                              'eight' => ''
                                            }
                               }
                    },
          'one' => {
                     'two' => {
                                'three' => ''
                              }
                   },
          'four' => ''
        };

Помните, Perl-хэши не упорядочены.

1 голос
/ 30 декабря 2010
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...