Сопоставление строк с целыми числами

Каков самый простой способ в Java сопоставить строки (Java String) с (положительными) целыми числами (Java int), так что

  • равные строки отображают равные целые числа, а
  • различные строки отображаются в разные целые числа?

Итак, подобно hashCode(), но для создания разных целых чисел требуются разные строки. Таким образом, в некотором смысле, это будет hasCode() без возможности столкновения.

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

Ответ 1

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

Решение возможно только при ограничении количества используемых строк. Затем вы можете использовать простой счетчик. Вот простая реализация, в которой могут использоваться все (2 ^ 32 = 4294967296 строк). Неважно, что он использует много памяти.

import java.util.HashMap;
import java.util.Map;

public class StringToInt {

    private Map<String, Integer> map;

    private int counter = Integer.MIN_VALUE;

    public StringToInt() {
        map = new HashMap<String, Integer>();
    }

    public int toInt(String s) {
        Integer i = map.get(s);
        if (i == null) {
            map.put(s, counter);
            i = counter;
            ++counter;
        }
        return i;
    }
}

Ответ 3

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

Ответ 4

В большинстве реализаций типа hashcode() коллизии принимаются как неизбежные и проверенные для.

Если вы абсолютно не должны иметь никаких коллизий, гарантированных, решение, которое вы наброски, будет работать.

Помимо этого существуют криптографические хеш-функции, такие как MD5 и SHA, где столкновения крайне маловероятны (хотя с большим усилием может быть принудительно). Архитектура криптографии Java реализует их. Эти методы могут быть быстрее, чем хорошая реализация вашего решения для очень больших наборов. Они также будут выполняться в постоянное время и давать одинаковый код для одной и той же строки, независимо от того, в какой порядок добавлены строки. Кроме того, он не требует сохранения каждой строки. Криптографические хэш-результаты можно рассматривать как целые числа, но они не будут вписываться в java int - вы могли бы использовать BigInteger, чтобы удерживать их, как было предложено в другом ответе.

Кстати, если вас отвлечет мысль о том, что столкновение "крайне маловероятно", вероятно, аналогичная вероятность того, что бит случайным образом перевернется в вашей памяти компьютера или жестком диске и приведет к тому, что любая программа будет вести себя иначе, чем вы ожидаете:-)

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

edit: Я только что заметил в заголовке вашего вопроса, кажется, вы хотите двунаправленное сопоставление, хотя на самом деле вы не утверждаете это в вопросе. Это (по дизайну) невозможно перейти от хеширования Crypto к исходной строке. Если вам это действительно нужно, вам нужно будет сохранить хэши ключей карты обратно в строки.

Ответ 5

Я попытался бы сделать, представив объект, содержащий карту и карту. Добавление строк к этому объекту (или, возможно, их создание из указанного объекта) присваивает им значение Integer. Запрос значения Integer для уже зарегистрированной String вернет то же значение.

Недостатки: разные запуски будут давать разные целые числа для одной и той же строки, в зависимости от порядка, если вы как-то не сохраните все это. Кроме того, он не очень объектно ориентирован и требует специального объекта для создания/регистрации строки. Плюс сторона: Это очень похоже на интернализацию строк и легко понятно. (Кроме того, вы попросили простой, а не элегантный способ.)

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

Ответ 6

Так как строки в java неограниченны по длине, и каждый символ имеет 16 бит, а ints имеет 32 бита, вы можете создать только уникальное сопоставление строк для int, если строки имеют до двух символов. Но вы можете использовать BigInteger для создания уникального сопоставления с чем-то вроде:

String s = "my string";
BigInteger bi = new BigInteger(s.getBytes());

Обратное отображение:

String str = new String(bi.toByteArray());

Ответ 7

Можете ли вы использовать карту, чтобы указать, к каким строкам вы уже назначили целые числа? Такое решение "database-y", где вы назначаете каждую строку "первичный ключ" из последовательности по мере ее появления. Затем вы вставляете пару String и Integer в карту, чтобы вы могли снова просмотреть ее. И если вам нужна строка для заданного целого, вы также можете поместить ту же пару в карту.

Ответ 8

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

Если вы замените "уникальный указатель" на "уникальное целое число", вы можете увидеть решение Dave Hanson для этой проблемы в C. Это довольно хорошая абстракция, потому что

  • Указатели все еще могут использоваться как строки C.

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

Если Java предлагает тест для идентификации объекта на объектах String, то вы можете играть там же.

Ответ 9

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

Однако, если вы просто имеете в виду положительное число, то теоретически вы должны уметь интерпретировать строку, как если бы она была "целым числом", просто рассматривая ее как массив байтов (в последовательной кодировке). Вы также можете рассматривать его как массив целых чисел произвольной длины, но если вы можете это сделать, просто не используйте строку?:)

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

Интересный вопрос.