Perl:使用List :: Util从多哈希获取最小距离值

时间:2016-11-29 17:59:59

标签: perl hash

我想从以下哈希获得与“snaffle”的最小距离:

$VAR1 = {
        '0' => {
                 'y' => '7012',
                 'snaffle' => {
                                '5' => {
                                         'y' => '3856',
                                         'x' => '875',
                                         'id' => '5',
                                         'distance' => 9734
                                       },
                                '6' => {
                                         'x' => '10517',
                                         'id' => '6',
                                         'distance' => 510,
                                         'y' => '6741'
                                       },
                                '4' => {
                                         'y' => '5291',
                                         'id' => '4',
                                         'x' => '11331',
                                         'target' => 'true',
                                         'distance' => 2125
                                       },
                                '8' => {
                                         'x' => '11709',
                                         'id' => '8',
                                         'distance' => 2236,
                                         'y' => '5475'
                                       },
                                '7' => {
                                         'distance' => 8485,
                                         'x' => '4591',
                                         'id' => '7',
                                         'y' => '544'
                                       }
                              },
                 'x' => '10084',
                 'distance2mybase' => 10598,
                 'distance2enemybase' => 6755,
                 'type' => 'WIZARD',
                 'id' => '0',
                 'state' => 0
               },

它很早就填满了:

# game loop
while (1) {
chomp(my $entities = <STDIN>); # number of entities still in game
for my $i (0..$entities-1) {
    chomp($tokens=<STDIN>);
    my ($entity_id, $entity_type, $x, $y, $vx, $vy, $state) = split(/ /,$tokens);
    my $type;

    if ($entity_type eq "WIZARD") {
        $type = "wizard";
    }
    if ($entity_type eq "OPPONENT_WIZARD") {
        $type = "enemy";
    }
    if ($entity_type eq "SNAFFLE") {
        $type = "snaffle";            
    }
    if ($entity_type eq "BLUDGER") {
        $type = "bludger";            
    }

    $entity{$type}{$entity_id}{x} = $x;
    $entity{$type}{$entity_id}{y} = $y;
    $entity{$type}{$entity_id}{state} = $state;
    $entity{$type}{$entity_id}{id} = $entity_id;
    $entity{$type}{$entity_id}{type} = $entity_type;
    $entity{$type}{$entity_id}{distance2mybase} = &getdistance($entity{$type}{$entity_id}{x},$entity{$type}{$entity_id}{y},$mybase_x,$mybase_y);
    $entity{$type}{$entity_id}{distance2enemybase} = &getdistance($entity{$type}{$entity_id}{x},$entity{$type}{$entity_id}{y},$enemybase_x,$enemybase_y);
}

foreach my $wizard_id (sort keys %{ $entity{'wizard'} }) {
    foreach my $snaffle_id (sort keys %{ $entity{'snaffle'} }) {
        $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{id} = $snaffle_id;
        $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{x} = $entity{'snaffle'}{$snaffle_id}{x};
        $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{y} = $entity{'snaffle'}{$snaffle_id}{y};
        $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{distance} = &getdistance($entity{'wizard'}{$wizard_id}{x},$entity{'wizard'}{$wizard_id}{y},$entity{'snaffle'}{$snaffle_id}{x},$entity{'snaffle'}{$snaffle_id}{y});
    }
&action($wizard_id,"sweep","up");
}

我尝试了List :: Util :: min,但我觉得我的搜索太深了,因为正如你在输出中看到的那样,它的目标是错误的snaffle。 (6距离低于4,这是当前目标)

我怎样才能找到所有马嚼子的总体最小距离? (万一你想知道,它是一个编码(.com))

sub snafflecheck {
my $wizard_id = shift;
my $wizard_x = shift;
my $wizard_y = shift;
if ($entity{'snaffle'}) {
    foreach my $snaffle_id (sort keys %{ $entity{'snaffle'} }) {
        my $snaffle_x = $entity{'snaffle'}{$snaffle_id}{x};
        my $snaffle_y = $entity{'snaffle'}{$snaffle_id}{y};

        my $distance2snaffle = &getdistance($wizard_x,$wizard_y,$snaffle_x,$snaffle_y);
        my $nearest = min $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{distance};


        if ($distance2snaffle) {
            if ($distance2snaffle == $nearest) {
                $entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{target} = "true";
                return("true",$entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{id},$entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{x},$entity{'wizard'}{$wizard_id}{snaffle}{$snaffle_id}{y},$distance2snaffle);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:3)

根据显示的数据,这是键distance

的所有值的列表
my @dist = map { $_->{distance} } values %{$entity->{0}{snaffle}};

然而,获得最小值并不能揭示其关键。

找到distance的值最小的键的一种方法

use List::Util 'reduce';

my $snaff = $entity->{0}{snaffle};

my $min_dist = reduce { 
    $snaff->{$a}{distance} < $snaff->{$b}{distance} ? $a : $b 
} keys %$snaff;

print "Minimal distance: $snaff->{$min_dist}{distance} for key $min_dist\n";

要获得更多控制权,您可以使用each迭代%$snaff

如果您想要全部使用$snaff distance,您还可以sort {/ 3}}。

答案 1 :(得分:1)

您应首先提取对snaffle哈希的引用,以使事情更加整洁。然后,您可以使用map提取每个哈希元素的distance字段,并min找到最小的哈希元素。

如果你想知道距离最小的马蹄那么 我建议您安装List::UtilsBy并使用其min_by运算符

此代码显示两个操作

哈希与您自己的哈希相同,但使用Data::Dump表示更紧凑

use strict;
use warnings 'all';
use feature 'say';

use List::Util 'min';
use List::UtilsBy 'min_by';

my %data = (
    "0" => {
        distance2enemybase => 6755,
        distance2mybase    => 10598,
        id                 => 0,
        snaffle            => {
            4 => { distance => 2125, id => 4, target => "true", x => 11331, y => 5291 },
            5 => { distance => 9734, id => 5, x      => 875,    y => 3856 },
            6 => { distance => 510,  id => 6, x      => 10517,  y => 6741 },
            7 => { distance => 8485, id => 7, x      => 4591,   y => 544 },
            8 => { distance => 2236, id => 8, x      => 11709,  y => 5475 },
        },
        state => 0,
        type  => "WIZARD",
        x     => 10084,
        y     => 7012,
    },
);

my $snaffles = $data{0}{snaffle};

my $min_distance = min map { $snaffles->{$_}{distance} } keys %$snaffles;
# OR
my $min_distance = min map { $_->{distance} } values %$snaffles;


my $closest_snaffle = min_by { $snaffles->{$_}{distance} } keys %$snaffles;

say "\$min_distance = $min_distance";
say "\$closest_snaffle = $closest_snaffle";

输出

$min_distance = 510
$closest_snaffle = 6