Java-эквивалент Perl-хэша

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

$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

Мне интересно, как я могу сделать то же самое с Java, я думаю, что это имеет какое-то отношение к HashMap?

Спасибо,

Ответ 1

Я использую много хэшей Perl из-за большой гибкости и удобства. например, в Perl я могу сделать следующее:      $hash{AREA_CODE}->{PHONE}->{STREET_ADDR}Мне интересно, как я могу сделать то же самое с Java, я думаю, что это имеет какое-то отношение к HashMap?

Код Java, который аппроксимирует следующий код Perl:

my %hash;
$hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};

есть

HashMap<String, HashMap<String, HashMap<String, String>>> hash =
    new HashMap<String, HashMap<String, HashMap<String, String>>>();

hash.put("AREA_CODE", new HashMap<String, HashMap<String, String>>());
hash.get("AREA_CODE").put("PHONE", new HashMap<String, String>());
hash.get("AREA_CODE").get("PHONE").put("STREET_ADDR", "221B Baker Street");

System.out.printf("Street address is %s\n",
    hash.get("AREA_CODE").get("PHONE").get("STREET_ADDR"));

Разве это не особенное?:)

Я говорю "приблизительные по многим причинам". Один из них заключается в том, что в Java вы будете разочарованы до крайнего апоплексирования просто для того, чтобы захотеть затем сделать на следующей строке Java эквивалент этого совершенно простого кода Perl:

$hash{AREA_CODE}{PREFIX} = 800;

Если вам нужна гибкость и удобство Perls в таких вещах, Java просто не даст вам это. Хуже того, его партизаны часто будут избивать вас за то, что они даже выражают такое желание.

Ответ 2

Смотрите Map интерфейс и его реализации, особенно HashMap.

Остерегайтесь того, что Java не имеет автоматической виртуализации Perl (удобная, но опасная), чтобы

hash.get("areaCode").get("phone").get("streetAdr")

выдаст исключение, если, например, get (phone) возвращает null. Остерегайтесь также, что вы не должны использовать хэши для вещей с фиксированными именами ( "свойства" ), вы должны определить свои собственные классы с помощью своих геттеров и сеттеров.

Ответ 3

Прежде всего, ваш конкретный пример ($hash{AREA_CODE}->{PHONE}->{STREET_ADDR}) с жестко закодированными строками в качестве хеш-ключей на самом деле не является полезной структурой данных на Java, как отметил Майкл Карман, - он должен храниться как класс с атрибутами ( и, честно говоря, это плохая структура данных в концепции - такие данные, как это, скорее всего, представляют собой массив телефонов, а не хэш телефонов).

Во-вторых, если вы действительно имели в виду $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}, похоже, что каждый Java-код до сих пор НЕ выполнял общий эквивалентный код - в коде все предполагалось, что хэш Java снова инициализирован для хранения примера ИЛИ полностью заполненного для примера поиска ( другими словами, как отмечалось в leonbloy, отсутствует функция автовивитации).

Правильная автовоспроизведение кода:

// This method will ensure that hash-of-hash-of-hashes structure exists of a given set of 3 keys.
public HashMap<String, HashMap<String, HashMap<String, Object>>>
 autovivification_3rd_level (
           HashMap<String, HashMap<String, HashMap<String, Object>>> hash
         , String AREA_CODE, String PHONE, String STREET_ADDR) {
    if (hash == null) {
        hash = new HashMap<String, HashMap<String, HashMap<String, Object>>>();
    }
    if (!hash.contains(AREA_CODE) || hash.get(AREA_CODE) == null) {
        hash.put(new HashMap<String, HashMap<String, Object>>());
    }
    HashMap<String, HashMap<String, Object>> AREA_CODE_hash
         = (HashMap<String, HashMap<String, Object>>) hash.get(AREA_CODE);
    if (!AREA_CODE_hash.contains(PHONE) || AREA_CODE_hash.get(PHONE) == null) {
        AREA_CODE_hash.put(new HashMap<String, Object>());
    }
    return hash;
}

////////////////////////////////////////////////////////////////////////////////////    

// Equivalent to Perl "$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR} = value;"
public Object put_3d_level_hash(
          HashMap<String, HashMap<String, HashMap<String, Object>>> hash
        , String AREA_CODE, String PHONE, String STREET_ADDR,
        , Object value) {
    hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
    return hash.get(AREA_CODE).get(PHONE).put(STREET_ADDR, value);
}
put_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR, obj);

////////////////////////////////////////////////////////////////////////////////////    

// Equivalent to Perl "$var = $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}"
public Object get_3d_level_hash(HashMap<String, HashMap<String, HashMap<String, Object>>> hash
                       , String AREA_CODE, String PHONE, String STREET_ADDR) {
    hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
    return hash.get(AREA_CODE).get(PHONE).get(STREET_ADDR);
}
Object obj = get_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR);

Ответ 4

Java имеет хеши, но из-за сильной типизации они не так гибки, как хэши в Perl. С многомерными хешами работать сложнее. В Perl вы можете просто объявить хэш и позволить автовивитации создавать вложенные хеши по запросу.

my %hash;
$hash{a}{b} = 1;

В Java, вы должны объявить его хэш-хешей вперед.

Map<String,Map<String,Integer>> hash = new HashMap<String,HashMap<String,Integer>>();
hash.put("a", new HashMap<String, Integer>());
hash.get("a").put("b", new Integer(1));

Для каждого дополнительного измерения вам нужно добавить еще одно вложение Map<K,V> в объявление. Помимо утомительности, это не очень OO.

Ответ 5

Если хеш-ключи являются постоянными, почему бы не сделать hash.getAreaCode().getPhone().getStreetAddr()? Имейте в виду, что либо ваши получатели, либо ваши конструкторы должны будут обрабатывать генерирование по умолчанию.

Ответ 6

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

От: $hash{AREA_CODE}->{PHONE}->{STREET_ADDR}

To: hash.vivifyingGet(areaCode).put(phone, streetAddr).

Предполагая, что я создал хеш с помощью

/**
  * A two-level autovivifying hashmap of X and Y to Z. Provides
  * a new method #vivifyingGet(X) which creates the next level of hash.
  */
Map<AreaCode, Map<Phone, StreetAddr>> hash =
    new HashMap<AreaCode, Map<Phone, StreetAddr>>() {
    /**
      * Convenience method to get or create the next level of hash.
      * @param key the first level key
      * @return the next level map
      */
    public Map<Phone, StreetAddr> vivifyingGet(Phone key) {
        if (containsKey(key)) {
            return get(key);
        } else {
            Map<Phone, StreetAddr> = hash = new HashMap<Phone, StreetAddr>();
            put(key, hash);
            return hash;
        }
    }
};

Ответ 7

Я пропустил perl хэши много в моей работе и сделал некоторые уродливые обходные пути с хэш-классами.

На прошлой неделе у меня возникла идея реализовать все в одном классе PerlMap, который использует разделители для доступа к объектам и, прежде всего, к подмножествам доступа t21.

Он отлично работает с map.get(code:street:phone) и map.put(code:street:phone,"123456789"). Чтобы получить список номеров, вы просто используете map.getList(code:street).

Я только что начал использовать его в своем проекте. У него нет ограничений сложности:-), и вы можете выбрать разделитель бесплатно. Я положил весь материал под http://www.jdeer.org. Повеселись.

Ответ 8

Вероятно, вам захочется пойти с Groovy, если вы хотите эту гибкость, но все еще выполняетесь в JVM. tchrist любит игнорировать тот факт, что Java строго типизирован, в отличие от динамически типизированных языков, таких как Perl или PHP, - и также любит игнорировать, что Java на порядок быстрее работает, но что только я являюсь "партизаном", по-видимому.