Desidero ottenere chiavi casuali e i rispettivi valori da una mappa. L'idea è che un generatore casuale prenda una chiave e visualizzi quel valore. La parte difficile è che sia la chiave che il valore saranno stringhe, ad esempio myMap.put("Geddy", "Lee")
.Selezione di chiavi e set di valori casuali da una mappa in Java
risposta
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);
Se non ti interessa lo spazio sprecato, un approccio sarebbe quello di mantenere separatamente un List
di tutte le chiavi che si trovano nello Map
. Per prestazioni ottimali, è necessario un List
con buone prestazioni ad accesso casuale (come un ArrayList
). Quindi, ottieni un numero casuale compreso tra 0 (incluso) e list.size()
(esclusivo), estrai la chiave in quell'indice e guarda quella chiave.
Random rand = something
int randIndex = rand.nextInt(list.size());
K key = list.get(randIndex);
V value = map.get(key);
Questo approccio significa anche che l'aggiunta di una coppia valore-chiave è molto più economica rispetto alla rimozione di una coppia chiave-valore. Per aggiungere la coppia valore-chiave, devi verificare se la chiave è già presente nella mappa (se i tuoi valori possono essere nulli, devi chiamare separatamente map.containsKey
; in caso contrario, puoi semplicemente aggiungere la coppia chiave-valore e vedere se il "vecchio valore" restituito è null)
. Se la chiave è già nella mappa, l'elenco è invariato, ma in caso contrario, si aggiunge la chiave alla lista (un'operazione O (1) per la maggior parte degli elenchi). La rimozione di una coppia valore-chiave, tuttavia, implica un'operazione O (N) per rimuovere la chiave dall'elenco
Se lo spazio è un grosso problema, ma le prestazioni lo sono meno, potresti anche ottenere un Iterator
sulla mappa set di voci (Map.entrySet()
) e salta le voci randIndex
prima di restituire quello desiderato.Ma sarebbe un'operazione di tipo O (N), che blocca l'intero punto di una mappa
Infine, è possibile ottenere il set di voci toArray()
e indicizzarlo a caso. È più semplice, anche se meno efficiente.
Questo è stato davvero utile. – Roberto
Questa domanda dovrebbe essere di aiuto a voi Is there a way to get the value of a HashMap randomly in Java? e questo anche perché Picking a random element from a setHashMap
è supportato da una HashSet
. Sarebbe il tempo O(n)
e lo spazio costante o sarebbe O(n)
spazio aggiuntivo e tempo costante.
Da un po 'di tempo da quando si gioca con java, ma non keySet() si fornisce un elenco che è possibile selezionare utilizzando un indice numerico? Penso che potresti scegliere un numero casuale e selezionarlo dal tasto Set di myMap, quindi selezionare il valore corrispondente da myMap. Non posso testarlo adesso, ma sembra che mi colpisca il più possibile!
No, come suggerisce il nome che restituisce un 'Set' e non un' Elenco'. Quindi sì, puoi scegliere una chiave a caso da un 'Set', ma non così semplice (né altrettanto veloce) come da un' Elenco' – Robin
Vorrei copiare la mappa in una matrice e selezionare la voce desiderata a caso. Questo evita la necessità di cercare anche il valore dalla chiave.
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)];
Se si vuole evitare la duplicazione, è possibile casuale l'ordine delle voci
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);
}
Utilizzare reservoir sampling per selezionare un elenco di chiavi casuali, poi inserirli in una mappa (insieme con i corrispondenti valori nella mappa sorgente)
In questo modo non è necessario copiare l'intero keySet
in un array, ma solo i tasti selezionati.
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);
}
. Cercherò di approfondirlo ulteriormente. – Roberto
se le chiavi sono integer o qualcosa di simile, è possibile utilizzare TreeMap per farlo.
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int key = RandomUtils.ranInt(treeMap.lastKey());
int value = treeMap.ceilingKey(key);
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()));
}
Quali sono i tuoi criteri di prestazione? C'è una soluzione O (n) per scegliere un elemento casuale da una sequenza arbitraria, ma se sceglierai elementi casuali un * lotto * dalla stessa mappa, potresti voler creare un elenco delle chiavi in modo da poter basta scegliere un numero casuale e passare da quello. –
Ho due modi che immagino: una chiave viene chiamata in modo casuale e visualizzata, l'utente inserisce un valore, il valore inserito viene confrontato con il valore memorizzato con la chiave. Dal mio esempio precedente, diciamo che all'utente viene chiesto "Qual è il cognome di Geddy?" (dove "Geddy" sarebbe preso come una stringa dalla chiave), l'utente inserisce "Smith". "Smith" viene quindi controllato rispetto al valore "Lee", ecc ... – Roberto