2016-07-26 43 views
1

你好Java的人,從Java HashMap中提取ith值的有效方法?

我正在學習Java HashMaps。雖然我喜歡將它們放在一起是多麼容易,但我正在研究如何以有效的方式從地圖中提取第i個條目。爲了解釋...

比方說,這是我的代碼:

package HashPackage; 

import java.util.HashMap; 

public class newHashObject { 

    // Nested class 
    public class newObject { 
     int Data1; 
     int Data2; 
     public newObject(int a, int b){ 
      this.Data1 = a; 
      this.Data2 = b; 
     } 
    } 

    // HashMap to contain newObjects 
    HashMap<Integer, newObject> cache = new HashMap<Integer, newObject>(); 

    // Constructor 
    public newHashObject(){ 
     // populate cache with 1000 newObjects: 
     for(int i=0; i<1000; i++) 
      cache.put(i, new newObject(i, i*2+101)); 
     System.out.println("New cache created, total objects in cache: "+cache.size()); 
    } 
} 

好了,沒有什麼激進至今。在現實生活中,我的HashMap中的條目不會以等於0,1,2,3 ......等等的密鑰進行歸檔,而是會用基本上隨機的數字鍵來歸檔。即如果你要檢查我的「現實生活」HashMap,你會看到鍵盤19,79,235,577,1023,1092等等。

現在我們假設我需要從哈希映射中提取出第i個元素。我不會提前知道關鍵的價值。例如,使用上面的「真實生活」地圖:如果我們開始將地圖的條目編號爲0,並且我想要取出第i = 4個條目,那麼我應該用鍵1023獲得條目。

我想過這一點,我想我可以通過從0我的HashMap只是重複,以我:

import java.util.Iterator; 
    ... 
    // Is there a better way to do this? 
    public newObject iterateByIndex(int index){ 
     Iterator<Integer> keySetIterator = cache.keySet().iterator(); 
     int count=0; 
     if(index<cache.size()){ 
      while(keySetIterator.hasNext()){ 
       Integer key = keySetIterator.next(); 
       if(count==index){ 
        // We've found the ith entry in the cache 
        return cache.get(key); 
       } 
       count++; 
      } 
     } 
     return null; 
    } 

此代碼的工作,但似乎笨重,如果絕對低效。我將需要調用這種方法數百萬次(不說謊!),並且從0到i的迭代每次都會是一個很大的時間消耗。

那麼......有什麼建議嗎? HashMap在這裏是錯誤的數據結構嗎? (我使用的是一個HashMap,因爲我的數據集非常大。)我很好奇在這種情況下更多經驗豐富的程序員可能會做什麼。

謝謝你的任何建議, -P

+7

如果您需要在「ith」元素的HashMap中引用某些內容,那麼您使用的數據結構錯誤。 – rmlan

+2

'HashMap'沒有定義的順序,所以「i-th」不是一個定義的概念。 「這個類不能保證地圖的順序,特別是它不能保證順序會隨着時間的推移保持不變。」 –

+1

具體來說,Map接口並未傳達任何排序。有一些有序的Map實現,比如TreeMap和LinkedHashMap。你可以看看那些。 (但應該指出,這些只是授予一個「可預測的迭代次序」 - 你不能只是要求第425次入門而不重複第一次424.不理想!) – dcsohl

回答

1

正如其名,「散列映射「,暗示,底層數據結構是一個」散列表「。從概念上講,它是一系列「桶」,關鍵是「散列」以確定要查找哪個(一個)桶以嘗試找到該密鑰。這是一個非常有效的數據結構,用於按價值查找鍵,但它沒有「順序」的概念。

Java有非常豐富的數據結構備選方案:各種樹,集合等等。即使好ol'陣列!您需要選擇更適合您需求的不同結構。 (請記住,某些東西可以是「in」......也就是說,「被......引用」......一次超過一個這樣的容器,就像SQL表格可能是一樣的有多個索引。)

+0

非常有幫助,謝謝!當我寫這個代碼的下一個版本時,我會考慮這些桶。 :) – Pete

3

HashMap不保留插入的順序。

如果你總是希望基於索引值或插入的次序排列,然後我會建議使用List實現像ArrayList其註冊就插入順序的檢索您的數據。

您可以在主數據對象周圍創建一個包裝對象,並將它們放在ArrayList中,當您需要閱讀它時,可以使用get方法使用您想要讀取的索引值。

2

HashMap不打算以這種方式使用,因爲條目的順序不能保證。如果您確實需要鍵值結構,則最好使用ArrayListLinkedHashMap

2

沒有有效的方法來從HashMap拉我的條目。事實上,從HashMap輸入的條目甚至都不是一個明確定義的概念,因爲HashMap中條目的排序是未指定的。

(相比之下,LinkedHashMap的條目可以按插入條目的順序進行迭代,但即使對於LinkedHashMap,也沒有辦法將條目從開始迭代開始「索引」,這是O(I)操作其中I是您嘗試檢索的元素的索引。)

底線:如果您希望使用索引進行有效查找(即O(1)),則應該使用ArrayList或基元數組。 (或者,也許可以使用索引值作爲你的哈希表的關鍵字,或者使用主哈希表中的條目的單獨哈希表。但是,那麼你是在談論一個更復雜的數據結構和/或一個不同的「索引」模型)。

+0

太棒了,謝謝Stephen!我希望有一個不同的答案,但沒關係 - 知道這些限制很酷。 :) – Pete

1

如果你不知道密鑰,那麼一個HashMap是相當無用的! 改爲使用ArrayList或類似的東西。

如果你的HashMap是真的,真的,真的很大(即,它不適合你無濟於事的記憶。),那麼你可以考慮使用的東西喜歡: http://www.oracle.com/technetwork/database/berkeleydb/overview/index-093405.html

+0

對不起,我真的想說「謝謝!」只是重讀先前的評論,並害怕它聽起來諷刺...如果是這樣,諷刺是完全無意的。 – Pete