【问题标题】:how to delete several items simultaneously from a ArrayList如何从 ArrayList 中同时删除多个项目
【发布时间】:2014-05-17 23:23:33
【问题描述】:

我的作业有问题,问题是我有大约 40.000 个 HashMap<Character,Character> 对象存储在 ArrayList<HashMap<Character,Character>>object 中。

每个对象HashMap<Character,Character> 对象代表一个替换密码的密钥。所以一个 HashMap 对象可能是:a->a; b->b; c->c; d->d; e->e; f->f; g->h; h->g 这意味着在加密/解密期间交换 g 和 h。

问题是我正在对这个密码进行暴力攻击,所以我正在循环访问这 40.000 个密钥。

当程序检测到说 g->h 这是一个错误的替换时,我想删除所有包含此条目的 HashMap 对象,而不仅仅是我在循环中使用的当前元素,因此能够避免一一检查键。

到目前为止,我已经尝试了以下方法,但它没有任何异常或任何事情都没有完成,甚至在调试时也没有完成:

  ArrayList<HashMap<Character,Character>> all_keys = new ...`
  all_keys = generateAllCombinations();`
  ArrayList<HashMap<Character,Character>> keys_to_delete = new ...`

  for(HashMap<Character,Character> key:all_keys){`
     all_keys.removeAll(keys_to_delete);
     \\other stuff going on...`
        if (!letters[0].getChar().equals(Constants.CHAR_E)){
         Character invChar = key.get(Constants.CHAR_E);
          for(HashMap<Character,Character> key2 : all_keys){
                if(key2.get(Constants.CHAR_E).equals(invChar)){
                 keys_to_delete.add(key2);
                }
          }

    }
   }

【问题讨论】:

  • 你可能想加强设计并使用真实的对象,也许引入一个Substitution(2个char字段fromto),那么你将在一个列表上工作的Substitution。回到你的问题,你正在修改一个你正在迭代的集合,这是被禁止的并抛出一个ConcurrentModificationException
  • 实际上,您可以修改您正在处理的集合,如果您使用迭代器而不是 foreach 循环,使用 iter.remove()。但这仍然不允许您执行 removeAll()。

标签: java arraylist hashmap


【解决方案1】:

前面已经提到,从当前迭代的集合中删除元素时必须小心。这可能很容易导致ConcurrentModificationException。对于不能轻易使用迭代器的“复杂”情况,通常可以应用的模式是,而不是做类似的事情

Collection<Element> collection = ...
for (Element element : collection)
{
    if (hasToBeRemoved(element)) 
    {
        // Will cause a ConcurrentModificationException!
        collection.remove(element);
    }
}

你收集要移除的元素,一次性全部移除

Collection<Element> collection = ...
Collection<Element> elementsToRemove = new List<Element>();
for (Element element : collection)
{
    if (hasToBeRemoved(element)) 
    {
        elementsToRemove.add(element);
    }
}
collection.removeAll(elementsToRemove);

根据代码,您似乎尝试过类似的操作,使用您的keys_to_delete,但这并不完全清楚。

正如评论中提到的,您应该考虑使用专用数据结构进行替换等。但即使您希望为此目的坚持使用列表和地图,您也应该始终使用 接口在声明中。所以而不是

ArrayList<HashMap<Character,Character>> allKeys = ...

你应该写

List<Map<Character,Character>> allKeys = ... 

但是,关于实际问题:似乎可以通过引入像 computeKeysContaining(maps, entry) 这样的方法来解决主要问题,该方法返回给定集合中包含特定条目的所有地图。

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class MapListKeyRemoval
{
    public static void main(String[] args)
    {
        List<Map<Character,Character>> allKeys = generateAllCombinations();

        print("All keys", allKeys);

        Set<Map<Character,Character>> keysToDelete = 
            new LinkedHashSet<Map<Character,Character>>();
        for (Map<Character, Character> key : allKeys)
        {
            for (Entry<Character, Character> entry : key.entrySet())
            {
                if (isInvalidMapping(entry))
                {
                    System.out.println("Invalid mapping: "+entry);
                    Set<Map<Character, Character>> keysWithInvalidMapping =
                        computeKeysContaining(allKeys, entry);

                    print("Keys with invalid mapping", keysWithInvalidMapping);

                    keysToDelete.addAll(keysWithInvalidMapping);
                }
            }
        }
        print("Keys to delete", keysToDelete);

        allKeys.removeAll(keysToDelete);

        print("All keys after removal", allKeys);
    }

    private static void print(
        String message, Iterable<Map<Character,Character>> keys)
    {
        System.out.println(message);
        for (Map<Character, Character> key : keys)
        {
            System.out.println(key);
        }
    }

    private static Set<Map<Character, Character>> computeKeysContaining(
        List<Map<Character,Character>> allKeys,
        Entry<Character, Character> entry)
    {
        Set<Map<Character,Character>> keysContainingEntry =  
            new LinkedHashSet<Map<Character,Character>>();
        for (Map<Character, Character> key : allKeys)
        {
            Object value = key.get(entry.getKey());
            if (value != null && value.equals(entry.getValue()))
            {
                keysContainingEntry.add(key);
            }
        }
        return keysContainingEntry;
    }

    private static boolean isInvalidMapping(Entry<Character, Character> entry)
    {
        return entry.getKey().equals('g') && entry.getValue().equals('h');
    }

    private static List<Map<Character, Character>> generateAllCombinations()
    {
        List<Map<Character, Character>> result = 
            new ArrayList<Map<Character,Character>>();
        result.add(createMapping('f','i','r','s','t','-','g','h'));
        result.add(createMapping('s','e','c','o','n','d','g','x'));
        result.add(createMapping('t','h','i','r','d','-','g','h'));
        result.add(createMapping('f','o','u','r','t','h','g','x'));
        return result;
    }

    private static Map<Character, Character> createMapping(char ... c)
    {
        Map<Character, Character> map = 
            new LinkedHashMap<Character, Character>();
        for (int i=0; i<c.length/2; i++)
        {
            map.put(c[i*2+0], c[i*2+1]);
        }
        return map;
    }
}

(除此之外,我想知道为什么回答问题的人是那些(必须)为这些简单的问题创建https://stackoverflow.com/help/mcve,但不想推测的人原因在这里)

【讨论】:

    【解决方案2】:

    使用迭代器。我的解决方案正在运行,但可能需要调整性能。

       Iterator<Map<String,String>> all_keys_iterator = all_keys.iterator();
       List<Map<String,String>> all_keys_new = new ArrayList<Map<String,String>> ();
    
       while(all_keys_iterator.hasNext()) {
        Map<String,String> copyMap = new HashMap<String,String> ();
    
        Map<String,String> all_keys_map = all_keys_iterator.next();
        for(String key: all_keys_map.keySet()) {
            if (!key.equalsIgnoreCase("key1")){
                copyMap.put(key, all_keys_map.get(key));
            }
        }
        if(!copyMap.isEmpty()) {
            all_keys_iterator.remove();
            all_keys_new.add(copyMap);
        }                      
       }
    
       all_keys.addAll(all_keys_new);
    
       for(Map<String,String> map: all_keys) {
        for(String key: map.keySet()) {
            System.out.println("key: " + key + " Value: " + map.get(key));
        }
       }
    

    【讨论】:

    • 我认为他想删除当前的 hashmap,以及包含相同映射的所有其他 hashmap。
    • @azurefrog 没错,我要删除几个hashmap元素。
    猜你喜欢
    • 2013-08-31
    • 2019-10-25
    • 1970-01-01
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    相关资源
    最近更新 更多