Лучшие практики для переопределения isEqual: и хеш

В Python> = 3.6 новая f-строка является эффективным способом конкатенации строки.

>>> name = 'some_name'
>>> number = 123
>>>
>>> f'Name is {name} and the number is {number}.'
'Name is some_name and the number is 123.'
265
задан Quinn Taylor 11 July 2009 в 02:49
поделиться

9 ответов

Запустите с

 NSUInteger prime = 31;
 NSUInteger result = 1;

Тогда для каждого примитива, который Вы делаете

 result = prime * result + var

Для 64 битов, которые Вы могли бы также хотеть сместить и xor.

 result = prime * result + (int) (var ^ (var >>> 32));

Для объектов Вы используете 0 для ноля и иначе их хэш-кода.

 result = prime * result + [var hash];

Для булевских переменных Вы используете два различных значения

 result = prime * result + (var)?1231:1237;
<час>

Объяснение и Атрибуция

, Это не работа tcurdt, и комментарии просили больше объяснения, таким образом, я полагаю, что редактирование для атрибуции справедливо.

Этот алгоритм был популяризирован в книге "Эффективный Java", и , соответствующая глава может в настоящее время находиться онлайн здесь . Та книга популяризировала алгоритм, который является теперь значением по умолчанию во многих JAVA-приложениях (включая Eclipse). Это произошло, однако, от еще более старой реализации, которая по-разному приписывается Dan Bernstein или Chris Torek. Тот более старый алгоритм, первоначально пущенный в ход вокруг в Usenet и определенной атрибуции, является трудным. Например, существуют [приблизительно 116] интересный комментарий в этом коде Apache (ищите их имена), это ссылается на первоисточник.

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

111
ответ дан fishinear 23 November 2019 в 02:28
поделиться

Обратите внимание, что при создании объекта, который может быть видоизменен после создания, значение хэш-функции должно не изменяться , если объект вставляется в набор. В сущности это означает, что значение хэш-функции должно быть зафиксировано от точки начального создания объекта. См. документация Apple относительно протокола NSObject - метод хеша для получения дополнительной информации:

, Если изменяемый объект добавляется к набору, который использует значения хэш-функции для определения object’s положения в наборе, значение, возвращенное методом хеша объекта, не должно изменяться, в то время как объект находится в наборе. Поэтому или метод хеша не должен полагаться ни на одну object’s информацию о внутреннем состоянии, или необходимо удостовериться, что object’s информация о внутреннем состоянии не изменяется, в то время как объект находится в наборе. Таким образом, например, изменяемый словарь может быть помещен в хэш-таблицу, но Вы не должны изменять его, в то время как это там. (Обратите внимание, что может быть трудно знать, является ли данный объект в наборе.)

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

2
ответ дан user10345 23 November 2019 в 02:28
поделиться

Я - новичок Objective C также, но я нашел превосходную статью об идентификационных данных по сравнению с равенством в Objective C здесь . От моего чтения похоже, что Вы могли бы быть в состоянии просто сохранить хеш-функцию по умолчанию (который должен обеспечить уникальные идентификационные данные), и реализуйте isEqual метод так, чтобы это сравнило значения данных.

4
ответ дан ceperry 23 November 2019 в 02:28
поделиться

Я нашел , эта страница , чтобы быть полезным руководством в переопределении равняется - и методы типа хеша. Это включает достойный алгоритм для вычисления хэш-кодов. Страница приспособлена к Java, но довольно легко адаптировать его к Objective-C/Cocoa.

5
ответ дан dasblinkenlight 23 November 2019 в 02:28
поделиться

Это непосредственно не отвечает на Ваш вопрос (вообще), но я использовал MurmurHash прежде для генерации хешей: Предположение murmurhash

я должен объяснить почему: murmurhash чертовски быстр...

5
ответ дан NANNAV 23 November 2019 в 02:28
поделиться

Легкий, но неэффективный путь состоит в том, чтобы возвратить тот же -hash значение для каждого экземпляра. Иначе, да, необходимо реализовать хеш, базирующийся только на объектах, которые влияют на равенство. Это хитро при использовании слабых сравнений в -isEqual: (например, нечувствительные к регистру сравнения строк). Для ints можно обычно использовать сам интервал, если you’ll соответствовать NSNumbers.

Don’t используют | =, тем не менее, это будет насыщать. Используйте ^ = вместо этого.

Случайный забавный факт: [[NSNumber numberWithInt:0] isEqual:[NSNumber numberWithBool:NO]], но [[NSNumber numberWithInt:0] hash] != [[NSNumber numberWithBool:NO] hash]. (rdar://4538282, откройтесь с 05 мая 2006)

13
ответ дан Jens Ayton 23 November 2019 в 02:28
поделиться

Я просто беру Objective C сам, таким образом, я не могу говорить за тот язык а именно, но на других языках я использую, если два экземпляра "Равны", они должны возвратить тот же хеш - иначе Вы собираетесь иметь все виды проблем при попытке использовать их в качестве ключей в хеш-таблице (или любые наборы типа словаря).

, С другой стороны, если 2 экземпляра не равны, они могут или не могут иметь того же хеша - лучше, если они не делают. Вот в чем разница между O (1) поиск на хэш-таблице и O (N) поиск - если все Ваши хеши сталкиваются, можно найти, что поиск таблицы не лучше, чем поиск списка.

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

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

81
ответ дан Brian B. 23 November 2019 в 02:28
поделиться

Куинн ошибается, что ссылка на хэш ропота здесь бесполезен. Куинн прав в том, что вы хотите понять теорию хеширования. Ропот превращает эту теорию в реализацию. Стоит изучить, как применить эту реализацию к этому конкретному приложению.

Некоторые из ключевых моментов здесь:

Пример функции из tcurdt предполагает, что '31' - хороший множитель, потому что он простое число. Нужно показать, что простота - необходимое и достаточное условие. На самом деле 31 (и 7), вероятно, не очень хорошие простые числа, потому что 31 == -1% 32. Нечетный умножитель с примерно половиной установленных бит и половиной битов свободными, вероятно, будет лучше. (Этим свойством обладает константа умножения хэша murmur.)

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

Установка начального результата на значение, при котором примерно половина битов равна нулю, а примерно половина битов равна единице, также может быть полезной.

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

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

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

3
ответ дан 23 November 2019 в 02:28
поделиться

Простите, если я рискну показаться здесь полным болваном, но ... ... никто не удосужился упомянуть, что для следования `` лучшим практикам '' вам определенно не следует указывать метод равенства, который НЕ будет учитывать все данные, принадлежащие вашему целевому объекту, например, любые данные, агрегированные для вашего объекта, по сравнению с его партнером, следует учитывать при реализации equals. Если вы не хотите принимать во внимание, скажем, «возраст» при сравнении, тогда вам следует написать компаратор и использовать его для выполнения сравнений вместо isEqual:.

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

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

1
ответ дан 23 November 2019 в 02:28
поделиться
Другие вопросы по тегам:

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