Лучше проверить ключи хеша Perl на истину или на существование?

8 ответов

Это зависит от того, нужен ли вам ключ или он должен иметь истинное значение. Проверьте то, что вам нужно. Если вы используете хеш просто для того, чтобы увидеть, есть ли что-то в списке, следует использовать exists (). Если вы делаете что-то еще, возможно, лучше всего будет проверить значение.

16
ответ дан 1 December 2019 в 00:33
поделиться

Если значения не нужны, вы часто будете встречать такую ​​идиому:

my %exists;
$exists{$_}++ for @list;

В результате значение устанавливается равным 1.

11
ответ дан 1 December 2019 в 00:33
поделиться

Если вы пытаетесь сэкономить память (что обычно имеет значение, только если у вас есть очень большой хеш), вы можете использовать undef в качестве значения и просто проверить его существование. Undef реализован как синглтон, поэтому тысячи undef - это просто указатели на одно и то же значение. Установка каждого значения в пустую строку или 1 выделит отдельное скалярное значение для каждого элемента.

my %exists;
@exists{@list} = ();

В свете вашего последующего комментария о вашем предполагаемом использовании, это идиома, которую я видел и использовал много раз:

my %seen;
while (<>) {
    next if $seen{$_}++; # false the first time, true every successive time
    ...process line...
}
9
ответ дан 1 December 2019 в 00:33
поделиться

Предположим, вам действительно нужно было проверить наличие ключей, но вы написали код, который проверяет истину. Он проверяет истину на протяжении всей вашей программы в разных местах. Затем внезапно выясняется, что вы что-то неправильно поняли и вам следует сохранить отображение ваших ключей в строковые значения; строки должны использоваться в том же потоке данных, что и вы уже реализовали.

И строки могут быть пустыми!

Следовательно, вам следует либо провести рефакторинг вашей программы, либо создать другой хэш, потому что проверка истинности больше не проверяет существование. Этого бы не произошло, если бы вы проверили существование с самого начала.

(отредактировано, потому что не знаю, почему вас отклонили.)

3
ответ дан 1 December 2019 в 00:33
поделиться

Как сказано в предыдущем ответе, это зависит от того, чего вы пытаетесь достичь; если вы просто пытаетесь получить (например) уникальные значения из некоторого набора (элементы которого затем образуют ключи), вы можете просто использовать exists (также может помочь отловить дубликаты, если вы сначала проверяете существование перед присвоением значения).

Не зная приложения, трудно быть более конкретным.

2
ответ дан 1 December 2019 в 00:33
поделиться

* Обновление: * Синан отмечает, что мой осторожный подход к созданию хеш-элементов устаревший и не проблема для новых Perls. Я отредактировал свой пост ниже и добавил несколько новых мыслей по этому поводу.

Проблема с простой проверкой на истину состоит в том, что вы можете изменить хэш с помощью хреновой старой версии Perl, которую я узнал на . Этот код безопасен с Perl 5.8:

my %foo = ();

if( $foo{bar} ) {
   print "never happens";
}

print keys %foo;

Это плохая часть смешанного благословения авто-вивификации (вообще-то мне нравится auto-viv, но здесь это больно).

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

На практике я либо заканчиваю, что всегда выполняю проверку существования перед проверкой логических значений.

if( exists $foo{bar} and $foo{bar} ) {
    # hash is not modified due to short circuit
}

Такое же изменение структур данных может происходить с массивами. Если вы получите доступ к $ foo [2000] , то массив будет расширен. Так что перед случайным расширением массива может быть хорошей идеей проверить его существование. На практике это было гораздо меньшей проблемой, чем соответствующее поведение хеширования. <- Ирония в том, что вы можете используется только в массиве на perls 5.6 и новее, где, предположительно, эта проблема была исправлена.

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

Самая важная вещь - согласованность в каждом скрипте / программе. Самый простой способ столкнуться с проблемами - это проверить существование здесь, а истины там. Особенно, если вы используете один и тот же хэш для обоих наборов тестов.

Заключительные мысли по поводу моего обновления, касающегося автовивификации: Шквал исследований показал несколько вещей. Мне следовало протестировать свой код перед публикацией - в противном случае я распространяю дезинформацию, за что прошу прощения. Я также обнаружил, что все еще остаются некоторые скрытые проблемы с автовивификацией - достаточно, чтобы есть открытая задача, чтобы все исправить . Так что, хотя это может быть ошибочным, старомодным и глупым, я продолжу явно предпринимать шаги для управления автовивификацией и ограничивать ее только , когда я хочу, чтобы это произошло. FWIW, автовивификация - отличная вещь, когда она работает. Я думаю, что специальный корпус if для предотвращения autoviv является правильным решением - это избавляет от необходимости в большом количестве дополнительного кода, но я хотел бы найти некоторые документы, которые подробно описывают это поведение.

Я буду продолжать явно предпринимать шаги для управления автовивификацией и ограничивать ее выполнение только , когда я хочу, чтобы это произошло. FWIW, автовивификация - отличная вещь, когда она работает. Я думаю, что специальный корпус if для предотвращения autoviv является правильным решением - это избавляет от необходимости в большом количестве дополнительного кода, но я хотел бы найти некоторые документы, которые подробно описывают это поведение.

Я буду продолжать явно предпринимать шаги для управления автовивификацией и ограничивать ее выполнение только , когда я хочу, чтобы это произошло. FWIW, автовивификация - отличная вещь, когда она работает. Я думаю, что специальный корпус if для предотвращения autoviv является правильным решением - это избавляет от необходимости в большом количестве дополнительного кода, но я хотел бы найти некоторые документы, которые подробно описывают это поведение.

3
ответ дан 1 December 2019 в 00:33
поделиться

Я обычно проверяю определенные значения. Это средний случай, который вы упускаете. Не совсем «правда», не совсем «существует» тоже. (В основном, но не совсем.)

Теоретически, более общий способ существует , как в

if ( exists $hash{$key} ) return 'strawberry';

. Это касается случая, когда ключ существует и значение равно 0 , или когда ключ был назначен undef . Чтобы пройти этот тест, ключ должен существовать .

Однако я редко обнаруживал необходимость проверить наличие ключа.

  1. Хэши часто являются частью определенного API, и если вы их обрабатываете, вы имеете некоторое представление о диапазоне значений, которые можно сохранить. Элемент конфигурации будет искать конкретные вещи; и как неупорядоченные ключи параметров, подпрограммы будут искать определенные вещи.

  2. Я считаю идею «бесконечной таблицы» очень гибкой концепцией. И существует x <=> определено x работает для этого. Каждое возможное значение «задано» в таблице, но определено только конечное число ключей , остальные считаются неопределенными.

    В результате, обычно, если значение не определено в хеше мне все равно, что это такое. Считаю это ложным значением. Хранение undef и полное отсутствие сохранения эквивалентны в большинстве вещей, которые я пишу. Это дополнительно мотивируется нижеследующим элементом.

  3. В большинстве случаев, когда мне может потребоваться узнать, есть ли ключ в таблице, мне нужно использовать его для чего-то другого. Сначала я сохраняю значение локально, а затем проверяю, соответствует ли определенное значение.

      my $ value = $ hash {$ key};
     if (определено $ value) { 
     нажмите @valid_values, $ value;
     }
    

    Если бы я мог быть уверен, что существует некоторая локальная оптимизация общего подвыражения между поиском для существует и поиском для использования значения, то я бы не был так придирчив к этому. Но я не люблю извлекать из хеша более одного раза. Поэтому я 1) кэширую значение и 2) проверяю его - каждый раз.

Тем не менее, я могу ужесточить критерии , если я знаю , что значение не должно быть 0 , например, в справочнике или в таблице параметров. Поэтому я иногда проверяю истину . Но я все равно могу ужесточить тест на что угодно.

     if ( ( $hash{$key} || '' ) =~ m/^(?:Bears|Lions|Packers|Vikings)$/ ) { 
         $nfc_north++;
     }
  1. Конечно, принцип работы здесь таков, что определенный работает для "неограниченных" таблиц. Где каждое мыслимое значение «задано» в таблице, но определено только конечное число ключей .

Есть случай, когда вы работаете над полностью анонимным хешем. Но тогда как вас интересуют ключи, которые не могут быть удовлетворены с помощью ключей или значений ? Даже если вы создаете универсальную хеш-функцию «для удобства», лучше не беспокоиться о существовании конкретных ключей, чтобы быть полностью нейтральным по отношению к тому, что кто-то там сохранил.

0
ответ дан 1 December 2019 в 00:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: