2013-10-17 19 views
0

我已經在stackflow中讀了一些關於ConcurrentModificationException的信息,並且我的實際更新似乎不是問題,它可能是我設計中的問題,或者我需要我還沒學過的技術。迭代器刪除/編輯是安全的,但是我也需要編輯以下所有迭代

示例情況: 我的迭代器沿着位置標記運行。 然後可以執行一個動作來移動標記(例如插入字符串)。 所有大於當前位置的標記也必須移位以保持正確性。

任務: 如何在沒有迭代器爆炸的情況下更新其餘標記? 我可以刷新迭代器,還是再次中斷並啓動循環?

下面的代碼是從我的工作中抽象出來的。

public void innerLoop(Boolean b) { 
    //An Example of what I'm working with 
    HashMap<String, HashSet<Integer>> map = new HashMap<String, HashSet<Integer>>() { 
     { 
      put("Nonce", 
       new HashSet<Integer>() { 

       { 
        add(1); 
        add(2); 
        add(3); 
        add(4); 
        add(5); 
       } 
      }); 
     } 
    }; 

    //for each key 
    for (String key: map.keySet()) { 
     HashSet<Integer> positions = map.get(key); 

     //for each integer 
     for (Iterator<Integer> it = positions.iterator(); it.hasNext();) { 
      Integer position = it.next(); 

      System.out.println("position =" + position); 
      //(out of scope) decision requiring elements from the outter loops 
      if (new Random().nextBoolean()&&b) { 
       //shift position by +4 (or whatever) 
       //and every other (int >= position) 
       System.out.println("Shift " + position + " by 4"); 
       Integer shift = 4; 
       update(position, 
         shift, 
         positions); 
       it.remove(); 
      } 
     } 
    } 
} 

public void update(Integer current, 
        Integer diff, 
        Set<Integer> set) { 

    if (set != null) { 
     HashSet<Integer> temp = new HashSet<Integer>(); 
     for (Integer old: set) { 
      if (old >= current) { 
       temp.add(old); 
       System.out.println(old + "Added to temp"); 
      } 
     } 

     for (Integer old: temp) { 
      set.remove(old); 
      System.out.println(old + "removed"); 
      set.add(old + diff); 
      System.out.println((old + diff) + "Added"); 
     } 
    } 
} 

與加勒特廳解決方案

public void nestedloops() { 

    HashMap<String, HashSet<Integer>> map = new HashMap<String, HashSet<Integer>>() { 
     { 
      put("Hello", 
       new HashSet<Integer>() { 

       { 
        add(5); 
        add(2); 
        add(3); 
        add(4); 
        add(1); 
        add(6); 
       } 
      }); 
     } 
    }; 

    //for each key 
    for (String key: map.keySet()) { 
     ArrayList<Integer> positions = new ArrayList<Integer>(map.get(key)); 
     //for each integer 
     for (int i = 0; i < positions.size(); i++) { 
      Integer position = positions.get(i); 
      System.out.println("[" + i + "] =" + position); 
      //out of scope decision 
      if (new Random().nextBoolean()) { 
       //shift position by +4 
       //and every other (int >= position) 
       System.out.println("Shift after " + position + " by 4"); 
       Integer shift = 4; 
       //Update the array 
       for (int j = 0; j < positions.size(); j++) { 
        Integer checkPosition = positions.get(j); 
        if (checkPosition > position) { 
         System.out.println(checkPosition + "increased by 4"); 
         positions.set(j, 
             checkPosition + shift); 
        } 
       } 
      } 
     } 
     //Add updated Array 
     map.put(key, 
       new HashSet<Integer>(positions)); 
    } 
} 

回答

1

您最好的選擇是通過將其加入列表索引HashSet編輯。然後,您可以使用索引來引用元素,而不是Iterator。只要您不刪除或添加(只更新)元素,那麼您的索引將是正確的。否則,你將不得不考慮這一點。例如:

ArrayList<Integer> positions = new ArrayList<Integer>(map.get(key)); 
for (int i = 0; i < positions.size(); i ++) { 
    // updating list 
    for (int j = i; i < positions.size(); j ++) { 
    positions.set(j, positions.get(i) + diff); 
    } 
} 
+0

看他的代碼,他實際上做的是這個... – libik

+0

map.keyset()返回設置 我需要 '爲(String鍵:map.keyset()){ ArrayList的位置=新的ArrayList (map.get(key));' 所以我沿着int整數移動,但只要不更改數組大小,我可以更改這些值? 最初看起來像我想要的,讓我檢查 –

+0

'ArrayList'應該以'position'在你當前的代碼中的相同方式實例化。 (用'map.get(key)'更新以反映這一點)。 –

0

我會將原始設置複製到列表中,以便您不必擔心當前的迭代代碼。然後更新輔助列表(未迭代)。

原因:

  1. 不能重複,並立即修改原始集合(也就是ConcurrentModificationExceptions周圍也沒有路)
  2. 尼斯one liner在列表中移動項目。

    Collections.rotate(list.subList(j, k+1), -1); 
    
  3. Guava將能夠處理「找到滿足該謂詞第一指數和改造名單」,這一串的實用方法。
+0

問:如果我有「editPositions」和「loopingPositions」。 在loopingPositions中,我發現我想要移位'position = 3'。 我更新'editPositions = {1,2,3 + 4,4 + 4,5 + 4} = {1,2,7,8,9}' loopingPositions的下一次迭代將'位置= 4',當我真的需要'position = 8'時已經過時了。那會發生什麼? –

+0

好了,沒有什麼可以阻止你在每次迭代交換原始列表它的副本,它們產生一個新的副本,將其旋轉,與以前的副本掉期等(它是昂貴的,但將工作)。視圖還可以緩解性能問題。 –

+0

一個更好的策略將包括「旋轉位置」的累積計數,那麼你總是考慮'loopingPosition + cumulativeCounter'爲偏移位置(以'0'開始)'editPositions',並且,在每次迭代結束時,使用'cumulativeCounter + = diff'這種方式,您可以遍歷原始值並仍然只使用原始集合的單個副本獲得所需的結果。 –