Sélection des clés et des ensembles de valeurs aléatoires à partir D'une carte en Java

je veux obtenir des clés aléatoires et leurs valeurs respectives d'une carte. L'idée est qu'un générateur de choisir une clé et d'afficher cette valeur. La partie délicate est que la clé et la valeur seront des chaînes, par exemple myMap.put("Geddy", "Lee") .

28
demandé sur Raedwald 2012-03-29 09:48:02

8 réponses

HashMap<String, String> x;

Random       random    = new Random();
List<String> keys      = new ArrayList<String>(x.keySet());
String       randomKey = keys.get( random.nextInt(keys.size()) );
String       value     = x.get(randomKey);
47
répondu synopia 2012-03-29 05:58:46

cette question devrait vous aider y a-t-il un moyen d'obtenir la valeur d'un HashMap au hasard en Java? et celui-ci aussi choisissant un élément aléatoire dans un ensemble parce que HashMap est soutenu par un HashSet . Il serait soit O(n) temps et espace constant ou il serait O(n) espace supplémentaire et temps constant.

4
répondu Narendra Yadala 2017-05-23 11:45:52

si vous ne vous souciez pas de l'espace perdu, une approche serait de garder séparément un List de toutes les clés qui sont dans le Map . Pour une meilleure performance, vous aurez besoin d'un List qui a une bonne performance d'accès aléatoire (comme un ArrayList ). Puis, il suffit d'obtenir un nombre aléatoire entre 0 (inclus) et list.size() (exclusif), retirer la clé à l'indice, et de regarder cette clé.

Random rand = something
int randIndex = rand.nextInt(list.size());
K key = list.get(randIndex);
V value = map.get(key);

cette approche signifie également que l'ajout d'une valeur paire est beaucoup moins cher que d'en enlever un. Ajouter la paire clé-valeur, vous pouvez tester pour voir si la clé est déjà dans la carte (si vos valeurs peuvent être nulles, vous devrez séparément appel map.containsKey ; si pas, vous pouvez simplement ajouter la paire clé-valeur et de voir si le "la vieille valeur" qu'elle renvoie est null) . Si la clé est déjà dans la carte, la liste est inchangée, mais si ce n'est pas le cas, vous ajoutez la clé à la liste (une opération O(1) pour la plupart des listes). La suppression d'une paire clé-valeur, cependant, implique une opération O(N) pour supprimer la clé de la liste.

si l'espace est un grand problème, mais la performance est moindre, vous pouvez également obtenir un Iterator sur l'entrée de la carte ( Map.entrySet() ), et sauter randIndex entrées avant de retourner celui que vous voulez. Mais ce serait une opération O(N), qui va à l'encontre du but d'une carte.

enfin, vous pouvez simplement obtenir l'ensemble d'entrée toArray() et l'index aléatoire dans cela. C'est plus simple, mais moins efficace.

3
répondu yshavit 2012-03-29 06:04:46

si vos clés sont entières, ou quelque chose de comparable, vous pouvez utiliser TreeMap pour le faire.

TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int key = RandomUtils.ranInt(treeMap.lastKey());
int value = treeMap.ceilingKey(key);
2
répondu archeryue 2015-03-30 04:32:08

Je copierais la carte dans un tableau et sélectionnerais l'entrée que vous voulez au hasard. Cela évite le besoin de chercher également la valeur de la clé.

Map<String, String> x = new HashMap<String, String>();
Map.Entry<String,String>[] entries = x.entrySet().toArray(new Map.Entry[0]);
Random rand = new Random();

// call repeatedly
Map.Entry<String, String> keyValue = entries[rand.nextInt(entries.length)];

si vous voulez éviter la duplication, vous pouvez randomiser l'ordre des entrées

Map<String, String> x = new HashMap<String, String>();
List<Map.Entry<String,String>> entries = new ArrayList<Map.Entry<String, String>> (x.entrySet());
Collections.shuffle(entries);
for (Map.Entry<String, String> entry : entries) {
    System.out.println(entry);
}
1
répondu Peter Lawrey 2012-03-29 06:59:13

Utiliser réservoir d'échantillonnage pour sélectionner une liste de clés aléatoires, puis de les insérer dans une carte (avec leurs valeurs correspondantes dans la carte source.)

de Cette façon, vous n'avez pas besoin de copier l'ensemble du keySet dans un tableau, seuls les clés.

public static <K, V>Map<K, V> sampleFromMap(Map<? extends K, ? extends V> source, int n, Random rnd) {
    List<K> chosenKeys = new ArrayList<K>();
    int count = 0;
    for (K k: source.keySet()) {
        if (count++ < n) {
            chosenKeys.add(k);
            if (count == n) {
                Collections.shuffle(chosenKeys, rnd);
            }
        } else {
            int pos = rnd.nextInt(count);
            if (pos < n) {
                chosenKeys.set(pos, k);
            }
        }
    }
    Map<K, V> result = new HashMap<K, V>();
    for (K k: chosenKeys) {
        result.put(k, source.get(k));
    }
    return Collections.unmodifiableMap(result);
}
1
répondu finnw 2012-03-30 23:02:26
In some cases you might want to preserve an order you put the elements in the Set,
In such scenario you can use, This 

Set<Integer> alldocsId = new HashSet<>();
            for (int i=0;i<normalized.length;i++)
            {
                String sql = "SELECT DISTINCT movieID FROM postingtbl WHERE term=?";
                PreparedStatement prepstm = conn.prepareStatement(sql);
                prepstm.setString(1,normalized[i]);
                ResultSet rs = prepstm.executeQuery();
                while (rs.next())
                {
                    alldocsId.add(rs.getInt("MovieID"));
                }
                prepstm.close();
            }

        List<Integer> alldocIDlst = new ArrayList<>();
        Iterator it = alldocsId.iterator();
        while (it.hasNext())
        {
            alldocIDlst.add(Integer.valueOf(it.next().toString()));
        }
0
répondu Jagesh Maharjan 2016-05-28 09:36:04

a joué avec java depuis longtemps, mais keySet() ne vous donne-t-il pas une liste que vous pouvez sélectionner à partir d'un index numérique? Je pense que vous pourriez choisir un nombre aléatoire et sélectionner cela à partir de la clé de MyMap, puis sélectionner la valeur correspondante à partir de myMap. Je ne peux pas le tester maintenant, mais ça me semble possible!

-1
répondu Michael Wheeler 2012-03-29 06:02:48