Perl

如何在雜湊而不是數組上使用 Perl grep?

  • December 17, 2019

我正在學習 Perl。我已經能夠grep在數組上使用並且語法非常簡單,比如這個例子

use strict; use warnings;

my @names = qw(Foo Bar Baz);
my $visitor = <STDIN>;
chomp $visitor;
if (grep { $visitor eq $_ } @names) {
  print "Visitor $visitor is in the guest list\n";
} else {
  print "Visitor $visitor is NOT in the guest list\n";
}

但是,我想知道是否有一種同樣簡單的方法可以grep在 hash 上使用而無需編寫循環來遍歷 hash 中的每個項目

這是我正在使用的結構的一些範例數據。在分配 URI 之前,我想檢查是否有任何項目已經具有該 uri 值。例如,我想分配ww1.example.com給 item v2rbz1568,但前提是沒有其他項目的 uri 值為ww1.example.com。我怎樣才能在 Perl 中有效地做到這一點?

{
   "0y7vfr1234": {
       "username": "user1@example.com",
       "password": "some-random-password123",
       "uri": "ww1.example.com",
       "index": 14
   },
   "v2rbz1568": {
       "username": "user3@example.com",
       "password": "some-random-password125",
       "uri": "ww3.example.com",
       "index": 29
   },
   "0zjk1156": {
       "username": "user2@example.com",
       "password": "some-random-password124",
       "uri": "ww2.example.com",
       "index": 38
   }
}

我在 Linux 上使用 perl 5,版本 30。

至少有兩種選擇:

  1. 您(僅)擁有您在問題中設想的資料結構。然後,每次要查找匹配項時,您都必須遍歷整個“列表”。您不必編寫循環,您可以使用該map函式:
use strict; use warnings;
my %entries = (
   '0y7vfr1234' => {
       'username' => 'user1@example.com',
       'password' => 'some-random-password123',
       'uri' => 'ww1.example.com',
       'index' => 14
   },
   'v2rbz1568' => {
       'username' => 'user3@example.com',
       'password' => 'some-random-password125',
       'uri' => 'ww3.example.com',
       'index' => 29
   }
);
my $uri = <STDIN>;
chomp $uri;
if (grep { $uri eq $_ } map { $_->{'uri'} } values %entries) {
  print "URI $uri is in the list\n";
} else {
  print "URI $uri is NOT in the list\n";
}
  1. 您在散列中管理一個單獨的索引,以便您可以進行快速查找。索引意味著您有一個單獨的雜湊映射 URI 到實際雜湊的項目:
use strict; use warnings;
my %entries = (
   '0y7vfr1234' => {
       'username' => 'user1@example.com',
       'password' => 'some-random-password123',
       'uri' => 'ww1.example.com',
       'index' => 14
   },
   'v2rbz1568' => {
       'username' => 'user3@example.com',
       'password' => 'some-random-password125',
       'uri' => 'ww3.example.com',
       'index' => 29
   }
);
my %index = map { $entries{"uri"} => $_ } keys %entries;

my $uri = <STDIN>;
chomp $uri;
my $item = $index{$uri};
if (defined($item)) {
  print "URI $uri is in the list\n";
} else {
  print "URI $uri is NOT in the list\n";
}

這也很方便,因為您可以$item直接作為查找的結果獲得print "Index: ",$entries{$item}->{'index'},"\n";

在第二種情況下,每次在“列表”中添加/更新/刪除 URI 時,您都必須手動更新索引:

$entries{"v84x9v8b9"} = { uri => "ww49", ... };
$index{"ww49"} = "v84x9v8b9";

引用自:https://unix.stackexchange.com/questions/557622