Je veux obtenir des clés aléatoires et leurs valeurs respectives à partir d'une carte. L'idée est qu'un générateur aléatoire sélectionne une clé et affiche cette valeur. La difficulté réside dans le fait que la clé et la valeur sont des chaînes, par exemple myMap.put("Geddy", "Lee")
.
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 Existe-t-il un moyen d’obtenir la valeur d’un HashMap au hasard en Java? et celui-ci aussi Choisir un élément aléatoire d'un ensemble parce que HashMap
est soutenu par un HashSet
. Ce serait soit O(n)
temps et espace constant, soit O(n)
espace supplémentaire et temps constant.
Si vous ne vous occupez pas de l'espace gaspillé, une solution serait de conserver séparément une List
de toutes les clés contenues dans la Map
. Pour obtenir de meilleures performances, vous souhaiterez une List
dotée de bonnes performances en accès aléatoire (comme une ArrayList
). Ensuite, obtenez simplement un nombre aléatoire compris entre 0 (inclus) et list.size()
(exclusif), extrayez la clé à cet index et recherchez-la.
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 paire clé-valeur coûte beaucoup moins cher que d'en supprimer une. Pour ajouter la paire clé-valeur, vous devez vérifier si la clé est déjà dans la carte (si vos valeurs peuvent être nulles, vous devrez appeler séparément map.containsKey
; sinon, vous pouvez simplement ajouter la paire clé-valeur. et voyez si "l'ancienne valeur" renvoyée est null)
. Si la clé est déjà dans la carte, la liste reste inchangée, mais si ce n'est pas le cas, vous l'ajoutez à la liste (une opération O(1) pour La suppression d’une paire clé-valeur implique toutefois une opération O(N) pour supprimer la clé de la liste.
Si l'espace est un gros problème, mais que les performances le sont moins, vous pouvez également obtenir une Iterator
sur l'ensemble des entrées de la carte (Map.entrySet()
) et ignorer les entrées randIndex
avant de renvoyer celle que vous voulez. Mais ce serait une opération O(N), qui aurait pour effet de vaincre le point entier d'une carte.
Enfin, vous pouvez simplement obtenir la fonction toArray()
du jeu d'entrées et y indexer de manière aléatoire. C'est plus simple, mais moins efficace.
si vos clés sont des nombres entiers 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);
Utilisez reservoir sampling pour sélectionner une liste de clés aléatoires, puis insérez-les dans une carte (ainsi que leurs valeurs correspondantes dans la carte source).
De cette façon, vous n'avez pas besoin de copier la totalité de la keySet
dans un tableau, uniquement les clés sélectionnées.
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);
}
Je copierais la carte dans un tableau et sélectionnerais l'entrée que vous voulez au hasard. Cela évite d'avoir à rechercher également la valeur dans 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 les doublons, 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);
}
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()));
}