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")
.
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);
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.
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.
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);
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);
}
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);
}
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()));
}
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!