web-dev-qa-db-de.com

Gibt es eine Möglichkeit, den Wert einer HashMap zufällig in Java abzurufen?

Gibt es eine Möglichkeit, den Wert einer HashMap zufällig in Java abzurufen?

30
Varuna

Sie könnten so etwas verwenden:

Random generator = new Random();
Map.Entry[] entries = myHashMap.entrySet().toArray();
randomValue = entries[generator.nextInt(entries.length)].getValue();

Update.

Das obige funktioniert nicht , Set.toArray() gibt immer ein Array von Objects zurück, das nicht in ein Array von Map.Entry umgewandelt werden kann.

Diese (einfachere Version) funktioniert:

Random generator = new Random();
Object[] values = myHashMap.values().toArray();
Object randomValue = values[generator.nextInt(values.length)];

Wenn Sie möchten, dass der Zufallswert ein anderer Typ als eine Object ist, fügen Sie der letzten Zeile einfach einen Cast hinzu. Wenn also myHashMap als deklariert wurde:

Map<Integer,String> myHashMap = new HashMap<Integer,String>();

Die letzte Zeile kann sein:

String randomValue = (String) values[generator.nextInt(value.length)];
48
Tom Jefferys

Da die Anforderungen nur einen zufälligen Wert von der HashMap verlangen, ist hier der Ansatz:

  1. Die HashMap hat eine values Methode, die eine Collection der Werte in der Karte zurückgibt.
  2. Die Collection wird verwendet, um eine List zu erstellen.
  3. Mit der size -Methode wird die Größe der List ermittelt, die von der Random.nextInt -Methode verwendet wird, um einen Zufallsindex der List zu erhalten.
  4. Schließlich wird der Wert von der Methode Listget mit dem Zufallsindex abgerufen.

Implementierung:

HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("Hello", 10);
map.put("Answer", 42);

List<Integer> valuesList = new ArrayList<Integer>(map.values());
int randomIndex = new Random().nextInt(valuesList.size());
Integer randomValue = valuesList.get(randomIndex);

Das Schöne an diesem Ansatz ist, dass alle Methoden generic - es gibt keine Notwendigkeit für Typumwandlung.

28
coobird

Wenn Sie weitere Werte aus der Karte ziehen müssen, ohne Elemente zu wiederholen, können Sie die Karte in eine Liste aufnehmen und sie anschließend neu mischen.

List<Object> valuesList = new ArrayList<Object>(map.values());
Collections.shuffle( valuesList );

for ( Object obj : valuesList ) {
    System.out.println( obj );
}
10
banjollity

Generieren Sie eine Zufallszahl zwischen 0 und der Anzahl der Schlüssel in Ihrer HashMap. Holen Sie sich den Schlüssel an der Zufallszahl. Holen Sie sich den Wert von diesem Schlüssel.

Pseudocode :

 int n =  random(map.keys().length());
 String key = map.keys().at(n);
 Object value = map.at(key);

Wenn dies in Java schwer zu implementieren ist, können Sie aus diesem Code ein Array erstellen, indem Sie die Funktion toArray() in Set verwenden.

 Object[] values = map.values().toArray(new Object[map.size()]);
 Object random_value = values[random(values.length)];

Ich bin nicht wirklich sicher, wie ich die Zufallszahl machen soll.

3
Peter Stuifzand

Eine gute Antwort hängt leicht von den Umständen ab, insbesondere davon, wie oft Sie einen zufälligen Schlüssel für eine bestimmte Karte erhalten müssen (Hinweis: Die Technik ist im Wesentlichen die gleiche, unabhängig davon, ob Sie einen Schlüssel oder einen Wert annehmen).

  • Wenn Sie verschiedene Zufallsschlüssel Von einer bestimmten Karte benötigen, ohne Änderung der Karte Zwischen dem Abrufen der Zufallsschlüssel, verwenden Sie die zufällig Abtastmethode, wenn Sie durch den Schlüsselsatz durchlaufen. Was Sie tatsächlich tun, ist eine Iteration über die von keySet () zurückgegebene Menge . Berechnen Sie für jedes Element __. Die Wahrscheinlichkeit, dass Diesen Schlüssel übernehmen möchte, wenn Sie bedenken, wie viele insgesamt und die Nummer, die Sie bisher genommen haben. Dann Eine Zufallszahl generieren und sehen, ob .__ diese Zahl niedriger ist als die Wahrscheinlichkeit. (N.B. Diese Methode wird immer funktionieren, auch wenn Sie nur einen Schlüssel benötigen; in diesem Fall ist es nicht unbedingt der effizienteste Weg.)
  • Die Schlüssel in einer HashMap sind bereits effektivin pseudozufälliger Reihenfolge. In einem Extremfall, in dem Sie nur Benötigen immer einen zufälligen Schlüssel für eine Gegebene mögliche Karte, können Sie sogar Das erstes Element von das keySet ().
  • In anderen Fällen (wo Sie entweder Mehrere mögliche Zufallsschlüssel Für eine gegebene mögliche Karte benötigen oder die Karte Zwischen zufälligen Schlüsseln wechselt), sind Sie im Wesentlichen muss Erstellen oder Verwalten eines Arrays/einer Liste der Schlüssel, aus denen Sie einen zufälligen Schlüssel auswählen.
1
Neil Coffey

Ich habe ein Dienstprogramm geschrieben, um einen zufälligen Eintrag, einen Schlüssel oder einen Wert von einer Karte, einem Eintragssatz oder einem Iterator abzurufen.

Da Sie die Größe eines Iterators nicht ermitteln können und sollen ( Guava kann dies ), müssen Sie die randEntry()-Methode überladen, um eine Größe zu akzeptieren, die der Länge der Einträge entspricht.

package util;

import Java.util.HashMap;
import Java.util.Iterator;
import Java.util.Map;
import Java.util.Map.Entry;
import Java.util.Set;

public class MapUtils {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<String, Integer>() {
            private static final long serialVersionUID = 1L;
            {
                put("Foo", 1);
                put("Bar", 2);
                put("Baz", 3);
            }
        };

        System.out.println(randEntryValue(map));
    }

    static <K, V> Entry<K, V> randEntry(Iterator<Entry<K, V>> it, int count) {
        int index = (int) (Math.random() * count);

        while (index > 0 && it.hasNext()) {
            it.next();
            index--;
        }

        return it.next();
    }

    static <K, V> Entry<K, V> randEntry(Set<Entry<K, V>> entries) {
        return randEntry(entries.iterator(), entries.size());
    }

    static <K, V> Entry<K, V> randEntry(Map<K, V> map) {
        return randEntry(map.entrySet());
    }

    static <K, V> K randEntryKey(Map<K, V> map) {
        return randEntry(map).getKey();
    }

    static <K, V> V randEntryValue(Map<K, V> map) {
        return randEntry(map).getValue();
    }
}
0
Mr. Polywhirl

Hier ist ein Beispiel für die Verwendung des von Peter Stuifzand beschriebenen Arrays-Ansatzes, auch durch die values()- Methode:

// Populate the map
// ...

Object[] keys = map.keySet().toArray();
Object[] values = map.values().toArray();

Random Rand = new Random();

// Get random key (and value, as an example)
String randKey = keys[ Rand.nextInt(keys.length) ];
String randValue = values[ Rand.nextInt(values.length) ];

// Use the random key
System.out.println( map.get(randKey) );
0
MH114

ich weiß wirklich nicht, warum Sie das tun wollen ... aber wenn es hilft, habe ich eine RandomMap erstellt, die die Werte beim Aufruf von values ​​() automatisch randomisiert. . 

  package random;

  import Java.util.ArrayList;
  import Java.util.Collection;
  import Java.util.Collections;
  import Java.util.HashMap;
  import Java.util.Iterator;
  import Java.util.List;
  import Java.util.Map;
  import Java.util.TreeMap;

  public class Main {
      public static void main(String[] args) {
          Map hashMap = makeHashMap();
          // you can make any Map random by making them a RandomMap
          // better if you can just create the Map as a RandomMap instead of HashMap
          Map randomMap = new RandomMap(hashMap);

          // just call values() and iterate through them, they will be random
          Iterator iter = randomMap.values().iterator();

          while (iter.hasNext()) {
              String value = (String) iter.next();
              System.out.println(value);
          }
      }

      private static Map makeHashMap() {
          Map retVal;

          // HashMap is not ordered, and not exactly random (read the javadocs)
          retVal = new HashMap();

          // TreeMap sorts your map based on Comparable of keys
          retVal = new TreeMap();

          // RandomMap - a map that returns stuff randomly
          // use this, don't have to create RandomMap after function returns
          // retVal = new HashMap();

          for (int i = 0; i < 20; i++) {
              retVal.put("key" + i, "value" + i);
          }

          return retVal;
      }
  }

  /**
   * An implementation of Map that shuffles the Collection returned by values().
   * Similar approach can be applied to its entrySet() and keySet() methods.
   */
  class RandomMap extends HashMap {
      public RandomMap() {
          super();
      }

      public RandomMap(Map map) {
          super(map);
      }

      /**
       * Randomize the values on every call to values()
       *
       * @return randomized Collection
       */
      @Override
      public Collection values() {
          List randomList = new ArrayList(super.values());
          Collections.shuffle(randomList);

          return randomList;
      }

  }
0
kctang

Normalerweise willst du nicht wirklich einen zufälligen Wert, sondern nur jeden Wert, und dann ist es schön, dies zu tun:

Object selectedObj = null;
for (Object obj : map.values()) {
    selectedObj = obj;
    break;
}
0
Kalisky

Das Konvertieren in ein Array und das Abrufen des Werts ist dann zu langsam, wenn sich der Pfad im aktuellen Pfad befindet.

holen Sie sich also das Set (entweder den Key- oder Keyvalue-Set) und machen Sie so etwas wie:

    public class SetUtility {
        public static<Type> Type getRandomElementFromSet(final Set<Type> set, Random random) {
        final int index = random.nextInt(set.size());

        Iterator<Type> iterator = set.iterator();

        for( int i = 0; i < index-1; i++ ) {
            iterator.next();
        }

        return iterator.next();
    }
0
Quonux