Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > Двойной ключ в HashMap


Автор: Opik 12.2.2007, 15:24
Как осуществить субж?
Например
Код

HashMap<Integer,String,User> t = new HashMap<Integer,String,User>();

Что мне нужно:
Возможность выдернуть юзера по ИД и по Сессии, будут какие предложения? А то я уже совсем запутался...

Автор: LSD 12.2.2007, 15:33
Используй MultiKey из Jakarta Commons Collections.

Автор: chief39 12.2.2007, 16:47
Гм, а сделать свой Key объект, который состоит из инта и стринга?
Определив hashcode, equals() 

Автор: y3u 12.2.2007, 17:15
И по сессии И по айдишнику - тогда можно просто сделать свой объектик, как и сказал chief39, а вот если ИЛИ по сессии ИЛИ по айдишнику, тогда не знаю, видимо, ка сказал LSD ... Тоже гляну на это мультикей

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

Автор: Opik 12.2.2007, 23:42
y3u, 
Нужно ИЛИ по сессии, ИЛИ по айди.
Multikey не подходит, т.к  там сразу по обоим критериям.
Насчет двух  хешмапов думал, но подумал, что есть более правильное решение.

Автор: LSD 13.2.2007, 11:52
Цитата(Opik @  12.2.2007,  15:24 Найти цитируемый пост)
выдернуть юзера по ИД и по Сессии

Цитата(Opik @  12.2.2007,  23:42 Найти цитируемый пост)
Нужно ИЛИ по сессии, ИЛИ по айди

Так И или ИЛИ? smile
Если ИЛИ, то можно и одной HashMap обойтись.
Код
HashMap hashMap = new HashMap();
String name = "Vasya";
Integer id = 1234;
String value = "Pupkin Vasya";
hashMap.put(name, value);
hashMap.put(id, value);

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

Автор: y3u 13.2.2007, 13:17
Цитата(LSD @  13.2.2007,  11:52 Найти цитируемый пост)
Если ИЛИ, то можно и одной HashMap обойтись.


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

Автор: LSD 13.2.2007, 14:23
Цитата(y3u @ 13.2.2007,  13:17)
а вот и нельзя smile Есть известное утверждение, что у двух идентичных объектов должен быть идентичный хешкод, но, если мы имеем два идентичных хешкода - отсюда НЕ следует, что объекты идентичные. Вполне легальны ситуации: коллекция не типизированная - значит хеши по стринге и по интеджеру могут совпасть, а если типизированная, то так сделать не даст компилятор smile

И какое это имеет отношение, к тому что я сказал?

Автор: y3u 13.2.2007, 15:16
Цитата(LSD @  13.2.2007,  14:23 Найти цитируемый пост)
И какое это имеет отношение, к тому что я сказал? 


прямое

Цитата(LSD @  13.2.2007,  11:52 Найти цитируемый пост)

Integer id = 1234;
String value = "Pupkin Vasya";
hashMap.put(name, value);
hashMap.put(id, value);


скажем, в 1.4 SDK посмотри как работает get(Object key) у HashMap... у тебя медленный код, т.к. хеши id и value могут быть одинаковыми, а реально объекты, находящиеся по этим ключам - разные

вобщем, ладно... это оффтоп smile

Автор: LSD 13.2.2007, 15:50
Цитата(y3u @  13.2.2007,  15:16 Найти цитируемый пост)
скажем, в 1.4 SDK посмотри как работает get(Object key) у HashMap... у тебя медленный код, т.к. хеши id и value могут быть одинаковыми, а реально объекты, находящиеся по этим ключам - разные

Вообще то, я прелагал искать value или по id, или по name smile 
И хеш код value в данном случае вообще неважен.

Добавлено @ 16:04 
Цитата(y3u @  13.2.2007,  15:16 Найти цитируемый пост)
скажем, в 1.4 SDK посмотри как работает get(Object key) у HashMap... у тебя медленный код, т.к. хеши id и value могут быть одинаковыми, а реально объекты, находящиеся по этим ключам - разные

Я знаю как работает HashMap. Совпадение хешей маловероятно, но не смертельно, в реальных задачах они все равно совпадают.

Автор: sergejzr 13.2.2007, 16:05
Цитата(y3u @  13.2.2007,  14:16 Найти цитируемый пост)
а реально объекты, находящиеся по этим ключам - разные

Почему они вдруг разные? И там и там указатель на один и тот же обьект.

Пишешь что-то вроде:
Код

class sessionMap extends HashMap
{
public void put(Object key, Object value)
{
//заглушка
}

public void put(Integer userId, Object value)
{
super.put(userId,value);
}
public void put(String sessionId, Object value)
{
super.put(sessionId,value);
}
public void put(Integer userId, String sessionId, User value)
{
super.put(userId,value);
super.put(sessionId,value);
}

public User get(Integer userId)
{
return super.get(userId);
}
public User get(String sessionId)
{
return super.get(sessionId);
}

}


Добавлено @ 16:06 
Цитата(y3u @  13.2.2007,  14:16 Найти цитируемый пост)
у тебя медленный код, т.к. хеши id и value могут быть одинаковыми, а реально объекты, находящиеся по этим ключам - разные

"Медленность" зависит от соотношения размера таблицы к количеству элементов в ней. Тут Ява сама подберёт оптимальную величину.

Автор: y3u 13.2.2007, 16:22
да блин, я описАлся, я имел в виду, конечно, name, а не value... Я вообще только о ключх говорю и все smile Не буду оффтопить дальше, скажу лишь, по поводу реальности задачи, что вероятность совпадения хешей и id и name в данном случае велика, причем вероятность увеличивается с ростом количества пользователей. Просто имеет смысл избегать нежелательных проблем с производительностью в тех случаях, где их реально можно избегать заранее просто и легко. Там же сначала берется хеш, достается индекс из таблицы, потом икуалс смотрится, если не совпадает ьерется следующее совпадение по хешу... Вы же не храните в одной банке соль и сахар на кухне...

Автор: sergejzr 13.2.2007, 16:29
Цитата(y3u @  13.2.2007,  15:22 Найти цитируемый пост)
что вероятность совпадения хешей и id и name в данном случае велика

Не больше, чем совпадение двух разных name.

Цитата(y3u @  13.2.2007,  15:22 Найти цитируемый пост)
причем вероятность увеличивается с ростом количества пользователей.

Не верно. С увеличением количества пользователей наша таблица будет расширятся и уменьшать таким образом вероятность совпадений.
(Размер кстати можно и изначально побольше задать)

Для практически равномерного распределения размер таблицы должен быть примерно N+20% где N - количество элементов хранимых таблице. Что это за объекты - не важно

Цитата(y3u @  13.2.2007,  15:22 Найти цитируемый пост)
Вы же не храните в одной банке соль и сахар на кухне... 

Нет, но книги разных авторов за разное время спокойно стоят на одной полке. И name и id - то и другое для хэштаблицы - объекты с калькулируемым идентификатором.

Автор: Opik 27.2.2007, 23:24
Написал класс, по совету chief39, 
Код

public class DoubleKey 
{
    Integer id; 
    String session;

    /** Creates a new instance of DoubleKey */
    public DoubleKey(Integer id, String session) 
    {
        this.id = id;
        this.session = session;
    }
    
    public boolean equals(Object o)
    {     
        if (o instanceof DoubleKey) 
        {
              DoubleKey d = (DoubleKey)o; 
              return d.id.equals(id) && d.session.equals(session); 
        } 
        else  
        { 
             return false; 
        }
    }
   

    public int hashCode()
    {
        return id.hashCode() ^ session.hashCode();               
    }
}


Добавляю в HashMap так:
Код

userslist.put(new DoubleKey(user.getId(), session), user);


Как мне бонально проверить на наличие сессии?
Код

userslist.containsKey(session);

не помогает
Код

userslist.containsKey(new DoubleKey(null, session));

аналогично

Автор: nornad 28.2.2007, 02:05
При такой реализации DoubleKey - никак. Точнее, никак за счёт containsKey. Простой перебор множества ключей сработает, но это простой перебор. В качестве заплатки сработает, если будешь пихать в мапу "пустышку" именно для возможности поиска по сессии:
Код

userslist.put(new DoubleKey(0, session), null);

Искать тогда так:
Код

userslist.containsKey(new DoubleKey(0, session));

null вместо идентификатора пихать нельзя, т.к. будет падать на NullPointer.

Автор: Opik 28.2.2007, 11:15
nornad, 
Если делать put - 0, тогда смысл во всей это байде отпадает совсем.

Автор: LSD 28.2.2007, 12:34
Цитата(Opik @  27.2.2007,  23:24 Найти цитируемый пост)
Как мне бонально проверить на наличие сессии?

А, никак smile Два DoubleKey будут равны только в случае совпадения и id и session. (ты просто реализовал свой MultiKey)

Единственный нормальный выход в данной ситуации - это 2 Map-а.

Автор: nornad 28.2.2007, 17:35
Цитата(Opik @  28.2.2007,  11:15 Найти цитируемый пост)
Если делать put - 0, тогда смысл во всей это байде отпадает совсем. 

А ты не думал, что ты хочешь слишком уж много? Тебе требуется, чтобы мапа различала ключи с разными id и session при вставке, и НЕ различала их по id при поиске ключа в мапе. Так не бывает. Это сродни тому, чтобы определить, есть ли в мапе по интам чётные ключи. Надо - перебери мапу или добавляй свои "пустышки". Не нужна такая "байда" - не ломай голову.  smile 

Автор: LSD 28.2.2007, 19:02
Цитата(LSD @  28.2.2007,  12:34 Найти цитируемый пост)
Единственный нормальный выход в данной ситуации - это 2 Map-а.

Вернее даже одним можно обойтись smile

Автор: Opik 28.2.2007, 19:03
LSD, 
Коим образом?

Автор: LSD 1.3.2007, 15:07
Да очень просто:
Код
  private Map map = new HashMap();

  public void put(Integer id, String session, Object value)
  {
    map.put(id, value);
    map.put(session, value);
  }

  public Object get(Integer id)
  {
    return map.get(id);
  }

  public Object get(String session)
  {
    return map.get(session);
  }

  public void remove(Integer id, String session)
  {
    map.remove(id);
    map.remove(session);
  }

Единственная проблема это метод remove() но тут уж ничего не поделаешь, кроме как завести еще один Map для установки соответствия id и session.

Автор: Opik 1.3.2007, 15:16
LSD, 
В этом случае все равно лучше уже 2 мапа. Впрочем остановился на 2-ух, пофиг smile

Автор: LSD 1.3.2007, 15:23
Значит считаем вопрос решенным?

Автор: Opik 1.3.2007, 15:24
Угу, уже пометил smile

Автор: nornad 1.3.2007, 18:16
Цитата(LSD @  1.3.2007,  15:07 Найти цитируемый пост)
Да очень просто:

Не совсем верно, потому что если у тебя будет два одинаковых идентификатора в разных сессиях или два разных идентификатора для одной сессии, то в мапе произойдёт наложение. В общем, мапа будет хранить не совсем то, что хочется.  smile 

Автор: LSD 1.3.2007, 18:23
Цитата(nornad @  1.3.2007,  18:16 Найти цитируемый пост)
Не совсем верно, потому что если у тебя будет два одинаковых идентификатора в разных сессиях или два разных идентификатора для одной сессии, то в мапе произойдёт наложение. В общем, мапа будет хранить не совсем то, что хочется.

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

Автор: nornad 1.3.2007, 22:15
Цитата(nornad @  1.3.2007, 18:16 Найти цитируемый пост)

Не совсем верно, потому что если у тебя будет два одинаковых идентификатора в разных сессиях или два разных идентификатора для одной сессии, то в мапе произойдёт наложение. В общем, мапа будет хранить не совсем то, что хочется.

Видимо, ты этого не заметил. ;)

Автор: LSD 2.3.2007, 12:46
Цитата(nornad @  1.3.2007,  22:15 Найти цитируемый пост)
Видимо, ты этого не заметил. ;)

Видимо ты не заметил smile 
Цитата(Opik @  12.2.2007,  23:42 Найти цитируемый пост)
Нужно ИЛИ по сессии, ИЛИ по айди.

Если ид или сессия не уникальны, то как ты предлагашь по ним искать?

Автор: nornad 2.3.2007, 18:32
Да, действительно не заметил этого. В памяти держалась лишь первоначальная задача - уникальность по двойному ключу, а в мапе надо было проверить, нет ли ключей с конкретной сессией.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)