【问题标题】:Can anyone explain how to print all keys if two keys are same but with different values?如果两个键相同但值不同,谁能解释如何打印所有键?
【发布时间】:2021-01-16 01:58:27
【问题描述】:

在此代码中,两个键“39”名称相同但值不同,我想打印两个键

use strict; 
use warnings; 

my %studentnames = ( 
14 => Martha, 
27 =>Vivek, 
31 =>Era, 
16 =>Marty, 
25 =>Jason, 
29 =>Socrates, 
19 =>Uri, 
39 =>Nitin , 
39 =>Plato, 
); 

foreach my $name (sort keys %studentnames) 
{ 
    printf "%-8s %s\n", $name, $studentnames{$name};
} 

我遇到了错误。

Bareword "Martha" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Vivek" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Era" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Marty" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Jason" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Socrates" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Uri" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Nitin" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.
Bareword "Plato" not allowed while "strict subs" in use at /home/9945b48d30946ed2641d9778b42cb182.pl line 10.

预期输出

14   Martha
27   Vivek 
31   Era
16   Marty 
25   Jason 
29   Socrates 
19   Uri
39   Nitin 
39   Plato

谁能告诉我怎么做?

【问题讨论】:

  • 使用这样的散列的建议很糟糕。你不应该鼓励更多的人在这个前提下解决这个问题。例如,在哈希中,数字 33.003 都将被视为不同,即使它们在数字上相同。您在这里创建的是一个 XY 问题。
  • 排序后的预期输出不完全清楚。您的目标是按学生编号排序,然后按学生姓名排序吗?在这种情况下,您为什么期望16 Marty 被排序 31 Era 之后?另外,名字是唯一的吗?还是数字 名称的组合是唯一的?如果没有任何东西本身或组合是唯一的,则哈希不是正确的数据结构,正如其他人所提到的,您需要一个数组。

标签: string perl hash


【解决方案1】:

两个键不能相同。一个会覆盖另一个。如果你想为一个键设置多个值,那么你需要设计你的数据结构来支持它(例如,让值是一个数组引用)。

您的错误消息与该问题无关(您忘记在字符串值周围加上引号)。

【讨论】:

    【解决方案2】:

    这有点接近:

    use strict;
    use warnings;
    use Tie::Hash::MultiValueOrdered;
    
    tie my %studentnames, 'Tie::Hash::MultiValueOrdered';
    %studentnames = (
        14 => 'Martha',
        27 => 'Vivek',
        31 => 'Era',
        16 => 'Marty',
        25 => 'Jason',
        29 => 'Socrates',
        19 => 'Uri',
        39 => 'Nitin',
        39 => 'Plato',
    ); 
    
    tied(%studentnames)->fetch_list;
    
    while ( my ( $key, $value ) = each %studentnames ) {
        print "$key => @$value\n";
    }
    

    但您确实想使用不同的数据结构。也许是一个arrayrefs 数组?

    use strict;
    use warnings;
    
    my @students = (
        [ 14 => 'Martha'   ],
        [ 27 => 'Vivek'    ],
        [ 31 => 'Era'      ],
        [ 16 => 'Marty'    ],
        [ 25 => 'Jason'    ],
        [ 29 => 'Socrates' ],
        [ 19 => 'Uri'      ],
        [ 39 => 'Nitin'    ],
        [ 39 => 'Plato'    ],
    ); 
    
    for my $student ( @students ) {
        my ( $num, $name ) = @$student;
        print "$num => $name\n";
    }
    

    或者一个hashrefs数组:

    use strict;
    use warnings;
    
    my @students = (
        { num => 14 , name => 'Martha'   },
        { num => 27 , name => 'Vivek'    },
        { num => 31 , name => 'Era'      },
        { num => 16 , name => 'Marty'    },
        { num => 25 , name => 'Jason'    },
        { num => 29 , name => 'Socrates' },
        { num => 19 , name => 'Uri'      },
        { num => 39 , name => 'Nitin'    },
        { num => 39 , name => 'Plato'    },
    ); 
    
    for my $student ( @students ) {
        print "$student->{num} => $student->{name}\n";
    }
    

    或者 arrayrefs 的哈希:

    use strict;
    use warnings;
    
    my %students = (
        14 => [ 'Martha'   ],
        27 => [ 'Vivek'    ],
        31 => [ 'Era'      ],
        16 => [ 'Marty'    ],
        25 => [ 'Jason'    ],
        29 => [ 'Socrates' ],
        19 => [ 'Uri'      ],
        39 => [ 'Nitin', 'Plato' ],
    ); 
    
    for my $key ( sort keys %students ) {
        for my $name ( @{$students{$key}} ) {
            print "$key => $name\n";
        }
    }
    

    或者您甚至可以创建一个轻量级的“人”类。

    use Z;
    
    my $Person = class sub {
        has num  => ( type => PositiveInt );
        has name => ( type => NonEmptyStr );
    };
    
    my @students = (
        $Person->new( num => 14, name => 'Marta'    ),
        $Person->new( num => 27, name => 'Vivek'    ),
        $Person->new( num => 31, name => 'Era'      ),
        $Person->new( num => 16, name => 'Marty'    ),
        $Person->new( num => 25, name => 'Jason'    ),
        $Person->new( num => 29, name => 'Socrates' ),
        $Person->new( num => 19, name => 'Uri'      ),
        $Person->new( num => 39, name => 'Nitin'    ),
        $Person->new( num => 39, name => 'Plato'    ),
    ); 
    
    for my $student ( @students ) {
        printf "%s => %s\n", $student->num, $student->name;
    }
    

    有很多方法可以解决这个问题,但单个扁平的字符串散列可能不是其中之一。

    【讨论】:

    • 你一直很忙! Z 的东西看起来很有趣。
    • my @students = map { $Person->new( ... ) } ...; :)
    【解决方案3】:

    首先:哈希值是字符串,因此需要引用。这就是您收到语法错误的原因:

    my %studentnames = ( 
        14 => 'Martha', 
        27 => 'Vivek', 
        31 => 'Era', 
        ... 
    ); 
    

    那么:对于 Perl 哈希是什么存在误解。散列中的每个键都必须是唯一的。 Perl 允许声明带有重复键的散列,但在底层,只保留每个键的最后一个值。

    所以这个:

    my %studentnames = ( 
        14 => 'Martha', 
        39 => 'Nitin', 
        39 => 'Plato' 
    ); 
    

    相当于:

    my %studentnames = ( 
        14 => 'Martha', 
        39 => 'Plato' 
    ); 
    

    另一种查看方式是将分配放在单独的说明中:

    my %studentnames;
    $studentnames{14} = 'Martha';
    $studentnames{39} = 'Nitin';
    $studentnames{39} = 'Plato';
    
    print $studentnames{39}, "\n";
    # Plato
    

    【讨论】:

      【解决方案4】:

      除了其他人提供的出色答案以及如何使代码工作的解释(例如,引用名称等),这里还有另一个简单的解决方案。我假设学生姓名是唯一的(因为它们确实出现在您的示例中)。在这种情况下,请使用散列的 reverse。即从数字到名字的映射改为名字到数字的映射。按数值(学生编号)对散列进行数字排序,然后按 ASCII 键(学生姓名)对哈希进行排序。这是我对一种对用户具有直观意义的可能排序方式的猜测。

      #!/usr/bin/env perl
      
      use strict;
      use warnings;
      
      my %student_name_to_num =
          reverse ( 
              14 => 'Martha', 
              27 => 'Vivek', 
              31 => 'Era', 
              16 => 'Marty', 
              25 => 'Jason', 
              29 => 'Socrates', 
              19 => 'Uri', 
              39 => 'Nitin', 
              39 => 'Plato', 
          ); 
      
      foreach my $name ( sort {
          $student_name_to_num{$a} <=> $student_name_to_num{$b} ||
              $a cmp $b
      } keys %student_name_to_num ) { 
          printf "%-8s %s\n", $student_name_to_num{$name}, $name;
      } 
      

      输出:

      14       Martha
      16       Marty
      19       Uri
      25       Jason
      27       Vivek
      29       Socrates
      31       Era
      39       Nitin
      39       Plato
      

      请注意,记录的顺序与您显示的排序顺序不同。但不清楚您希望如何对记录进行排序(另请参阅我在问题下的评论)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-17
        • 2017-04-07
        • 2016-11-23
        • 1970-01-01
        相关资源
        最近更新 更多