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

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

8 голосов
/ 22 января 2011

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

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

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

Спасибо,

Ответы [ 8 ]

18 голосов
/ 22 января 2011

Я использовал много 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;

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

5 голосов
/ 22 января 2011

Прежде всего, ваш конкретный пример ($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's "$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's "$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);
5 голосов
/ 22 января 2011

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

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

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

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

2 голосов
/ 22 января 2011

У 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> в объявление. Помимо того, что утомительно, это не очень хорошо.

1 голос
/ 07 марта 2011

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

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

Кому: 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;
        }
    }
};
1 голос
/ 22 января 2011

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

0 голосов
/ 27 февраля 2012

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

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

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

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

0 голосов
/ 22 января 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...