2017-02-05 2 views
2

Прежде всего, я хотел бы сказать, что я довольно новичок в программировании. Я храню несколько «расширений» суперкласса в том же HashMap. (например, XY и XZ расширяет X - I хранят как X, XY, так и XZ в одном и том же HashMap). Я решил сделать это для удобства - обычно каждый раз, когда я что-то делаю, мне нужны все классы, которые расширяют «X» - в этом примере «XY» и «XZ». Также нет проблем, когда я хочу проверить, является ли одиночное значение экземпляром указанного типа объекта - я просто использую формулу «instanceof». Допустим, что я хочу, чтобы проверить, если объект ключ «ключ» является экземпляром «XY»:Получить соответствующий тип объекта из HashMap

X objectoftypeX = hashmap.get(key) 
if(objectoftypeX instanceof XY){ 
    //do stuff 
} 

Но вот мой вопрос приходит: как итерацию только через, например, XY-х в этом HashMap? Возможно ли это без проверки каждого отдельного объекта отдельно? Имеет ли смысл делать это? Надеюсь, вы поймете мою проблему.

ответ

5

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

Например, вы можете выбрать, чтобы сделать несколько карт, или сделать вложенную карту:

// Nested map, with the top level map indexing by Type (can be a String) 
// and the maps inside it indexing by a String key. 
Map<Type, Map<String, Object>> map = ...; 

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

List<XY> list = hashmap.values().stream() 
    .filter(v -> v instanceof XY) // check type 
    .map(v -> (XY) v) // do cast 
    .collect(Collectors.toList()); // collect to list 
2
hashmap.entrySet().filter(item -> item.value() instanceOf X).forEach(item -> ...); 

это то же самое, но shoter

+1

Я не думаю, что клавиши имеют тип X, XY, XZ :) – john16384

+0

Спасибо) просто ошибка, исправлено это – dmitryvim

0
final Object[] keySetArray = mMap.keySet().toArray(); 
for(int x = 0; x < keySetArray.length; x++) 
{ 
     final Object whatStored = mMap.get(keySetArray[x]); 
     System.out.println("key[" + keySetArray[x] + "]: "+ whatStored); 
    // Make sure this check happens as it is, if you stored XY and XZ that extended X 
     if(whatStored instanceof of XY || whatStored instanceof XZ) 
     { 
      if(whatStored instanceof XY) 
      { 
        // Go here for instance X and XY 
      } 
      else if(whatStored instanceof XZ) 
      { 
       // Go here for instance X and XZ 
      } 
     } 
} 

Надеюсь, что это близко?

+0

Я думаю, что это близко, но немного сложнее, чем нужно. –

0

Со стандартным hashmap его невозможно сделать эффективно (без прохождения всего). Цель hashmap - обеспечить быстрый доступ к элементам с небольшими издержками памяти. У вас есть массив с целым размером и функцией hashcode, которая возвращает целое число для каждого сохраненного объекта. Затем вы сможете найти элемент, применив index = hashcode (key), который в основном выполняет 1 операцию, чтобы найти что-либо. Но у вас ужасная память (размер массива равен всем целым числам).

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

Hashmap находится посередине. Вы выделяете массив размера, скажем 100. Затем вы вычисляете функцию hashcode для ключа, а результат - 105. Таким образом, вы помещаете объект в индекс {hashcode_result} по модулю array_size. В нашем случае 105% 100 == 5.

Интересный материал зависит от реализации, что вы будете делать, если у вас есть столкновение, которое в качестве ключа2 с тем же позитивом. Например, если значение hashcode равно 205, 305 ... (по модулю будет 5 для всех этих хэш-кодов). Одной из возможностей было бы добавить эти дополнительные элементы в следующий доступный индекс 6, 7 ... В Java (или, по крайней мере, насколько я помню) ковши выполнены в виде связанных списков, так что вы будете иметь

0 => [] 
1 => [] 
2 => [] 
3 => [] 
4 => [] 
5 => [k=105, k=205, k=305...] 

Единственный способ, как использовать HashMap для случая использования будет реализовать функцию Hashcode , который всегда генерирует один и тот же хэш для одного и того же класса. Но это приведет к вырождению хэш-карты в n списков, где n - количество подклассов. И поиск будет ужасно страдать (вам нужно будет выполнять операции M/n для поиска значения, где M - количество элементов, а n - количество различных классов), а правильно реализованный hashmap (равномерное распределение значений хэш-кода) гарантирует, что число выборок будет эффективно равна 1.


Короче говоря - из-за структуры HashMap, вы не можете сделать любой тип loopkup данных в зависимости от эффективного (вы Виль убить производительность для поиска через списки). Если вы хотите иметь этот тип поиска, ответ john16384 действительно хороший.

Смежные вопросы