web-dev-qa-db-fra.com

Sélection de jeux de clés et de valeurs aléatoires à partir d'une carte en Java

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").

29
Roberto
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);
48
synopia

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. 

4
Narendra Yadala

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.

3
yshavit

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);
2
archeryue

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);
}
1
finnw

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);
}
1
Peter Lawrey
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
Jagesh Maharjan