有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何洗牌键值对?

我有一套价值观需要在需要时进行调整。 我不知道哪种变量类型最适合我。数据实际上是基于键值结构的。像

100 "white"
200 "black"
300 "red"

就这样。我想做的是根据我还不知道的一些算法来更改键值对。但是它们需要像这样被洗牌,但是洗牌需要不是随机的,所以我可以在需要的时候恢复数据

100 "red"
200 "white"
300 "black"

我真的不知道我应该如何解决这个问题。我应该使用HashTable还是其他什么,如何动态地洗牌它们? 任何帮助都将不胜感激


共 (3) 个答案

  1. # 1 楼答案

    随机洗牌键值映射的另一种方法:

    public static <K,V> void shuffleMap(Map<K,V> map) {
        List<V> valueList = new ArrayList<V>(map.values());
        Collections.shuffle(valueList);
        Iterator<V> valueIt = valueList.iterator();
        for(Map.Entry<K,V> e : map.entrySet()) {
            e.setValue(valueIt.next());
        }
    }
    

    编辑:

    如果不想更改原始地图(因为以后需要),可以创建一个新地图:

    public static <K,V> Map<K,V> shuffleMap(Map<K,V> map) {
        List<V> valueList = new ArrayList<V>(map.values());
        Collections.shuffle(valueList);
        Iterator<V> valueIt = valueList.iterator();
        Map<K,V> newMap = new HashMap<K,V>(map.size());
        for(K key : map.keySet()) {
            newMap.put(key, valueIt.next());
        }
        return newMap;
    }
    

    你并不是真的想要一个看似随机的混音,它可以被还原(很快就会变得复杂),而是简单地保留你的原始地图。如果这不合适,你需要更好地描述你的问题


    好的,你想用一个密钥加密映射,给出另一个映射,然后再次解密。显然,随机洗牌在这里没有帮助,甚至伪随机也没有好处,因为它没有提供可靠的洗牌方式。在基本情况下,你的键是映射键之间的可逆映射

    public static <K,V> Map<K,V> encryptMap(Map<K,V> plainMap, Map<K,K> key) {
        Map<K,V> cryptoMap = new HashMap<K,V>(plainMap.size());
        for(Map.Entry<K,V> entry : plainMap.entrySet()) {
           cryptoMap.put(key.get(entry.getKey()), entry.getValue());
        }
        return cryptoMap;
    }
    

    事实上,解密的工作原理是相同的,只使用密钥的反向映射

    因此,当您有{100, 200, 300}的示例密钥时,这些密钥的任何排列都是我们的“加密方案”的有效密钥。 (只有6种可能,这不是很安全。)

    Map sampleKey = new HashMap<Integer, Integer>();
    sampleKey.put(100, 200);
    sampleKey.put(200, 300);
    sampleKey.put(300, 100);
    
    Map sampleUnKey = new HashMap<Integer, Integer>();
    for(Map.Entry<Integer, Integer> e : sampleKey) {
       sampleUnKey.put(e.getValue(), e.getKey());
    }
    
    Map<Integer, String> data = new HashMap<Integer, String>();
    data.put(100, "white");
    data.put(200, "black");
    data.put(300, "red");
    
    System.out.println(data);
    
    Map<Integer, String> encrypted = encryptMap(data, sampleKey);
    
    System.out.println(encrypted);
    
    Map<Integer, String> decrypted = encryptMap(data, sampleUnKey);
    
    System.out.println(decrypted);
    

    地图decrypted现在应该与原始地图相同

    对于更大的密钥集,您需要找到一个方案来获得合适的密钥 一些可输入密钥的密钥排列

  2. # 2 楼答案

    看起来你需要一个元组列表。地图就是这样。但是,HashMap这样的标准没有更改键和值之间关系的功能

    我想我应该为这个实现我自己的地图。创建一个实现java的类。util。映射、实现所需的方法,并创建其他一些“混合”方法

    这一切都取决于tuple列表中真正需要的功能。你需要快速查找颜色吗?可以有多个具有相同数字的元组吗

  3. # 3 楼答案

    我不确定你将如何确切地洗牌这些对,但如果你需要根据密钥洗牌,你可以使用^{

    Map<String, String> map = new HashMap<String, String>();
    map.put("100", "white");
    map.put("200", "black");
    map.put("300", "red");
    
    // swap 100 with 200
    String temp = map.get("100");
    map.put("100", map.get("200"));
    map.put("200", temp);
    

    或者,如果需要随机洗牌这对,可以按照larsmans的建议创建一个类Pair(它基本上存储一个int和一个String),并将它们存储在一个数组中。然后,可以使用稍微修改过的^{}版本。大致如下:

    // initialize list
    List<Pair<Integer, String>> values = new ArrayList<Pair<Integer, String>>();
    values.add(new Pair<Integer, String>(100, "white"));
    values.add(new Pair<Integer, String>(200, "black"));
    values.add(new Pair<Integer, String>(300, "red"));
    
    // shuffle
    System.out.println(values); // e.g., [100 white, 200 black, 300 red]
    Random random = new Random();
    for (int i = values.size() - 1; i > 1; i ) {
        int j = random.nextInt(i + 1);
        // swap values between i-th Pair and j-th Pair
        Pair<Integer, String> iPair = values.get(i); // the iPair :-)
        Pair<Integer, String> jPair = values.get(j);
        String iString = iPair.getSecond();
        iPair.setSecond(jPair.getSecond());
        jPair.setSecond(iString);
    }
    System.out.println(values); // e.g., [100 red, 200 black, 300 white]