Есть ли способ получить значение HashMap случайным образом в Java? - PullRequest
34 голосов
/ 30 мая 2009

Есть ли способ получить значение HashMap случайным образом в Java?

Ответы [ 11 ]

50 голосов
/ 30 мая 2009

Это работает:

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

Если вы хотите, чтобы случайное значение было типом, отличным от Object, просто добавьте приведение к последней строке. Так что если myHashMap было объявлено как:

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

Последняя строка может быть:

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

Нижеследующее не работает , Set.toArray() всегда возвращает массив Object с, который нельзя привести к массиву Map.Entry.

Random generator = new Random();
Map.Entry[] entries = myHashMap.entrySet().toArray();
randomValue = entries[generator.nextInt(entries.length)].getValue();
30 голосов
/ 30 мая 2009

Поскольку требования запрашивают только случайное значение из HashMap, вот подход:

  1. HashMap имеет метод values, который возвращает Collection значений на карте.
  2. Collection используется для создания List.
  3. Метод size используется для определения размера List, который используется методом Random.nextInt для получения случайного индекса List.
  4. Наконец, значение извлекается из метода List get со случайным индексом.

Реализация:

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

Приятной особенностью этого подхода является то, что все методы являются универсальными - нет необходимости в приведении типов.

10 голосов
/ 30 мая 2009

Если вам нужно нарисовать дополнительные значения с карты без повторения каких-либо элементов, вы можете поместить карту в список и затем перемешать ее.

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

for ( Object obj : valuesList ) {
    System.out.println( obj );
}
3 голосов
/ 30 мая 2009

Генерирует случайное число от 0 до количества ключей в вашем HashMap. Получите ключ по случайному номеру. Получить значение из этого ключа.

псевдокод

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

Если это трудно реализовать на Java, вы можете создать и создать массив из этого кода, используя функцию toArray() в Set.

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

Я не совсем уверен, как сделать случайное число.

1 голос
/ 29 мая 2015

Преобразование его в массив и последующее получение значения происходит слишком медленно, когда он находится в горячем пути.

, поэтому получите набор (ключ или набор значений ключей) и сделайте что-то вроде:

    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();
    }
1 голос
/ 07 мая 2012

Обычно вы на самом деле не хотите случайное значение, а просто любое значение, и тогда приятно делать это:

Object selectedObj = null;
for (Object obj : map.values()) {
    selectedObj = obj;
    break;
}
1 голос
/ 30 мая 2009

Хороший ответ слабо зависит от обстоятельств, в частности, от того, как часто вам нужно получить случайный ключ для данной карты (примечание: техника, по сути, одинакова независимо от того, берете ли вы ключ или значение).

  • Если вам нужно различные случайные ключи с данной карты, без карты изменение между получением случайные ключи, затем используйте случайные метод выборки во время итерации через набор ключей. Эффективно что вы делаете, перебираете множество возвращается keySet (), и на каждом пункт рассчитать вероятность желая взять этот ключ, учитывая, как много вам нужно в целом и номер, который вы взяли до сих пор. затем генерировать случайное число и посмотреть, если это число меньше, чем вероятность. (N.B. Этот метод всегда будет работать , даже если вам нужен только 1 ключ; в этом случае это не обязательно самый эффективный способ.)
  • Ключи в HashMap эффективно в псевдослучайном порядке уже. В крайний случай, когда вы будете только когда-нибудь нужен один случайный ключ для учитывая возможную карту, вы могли бы даже просто вытащите первый элемент Keyset () .
  • В других случаях (где вы либо нужно несколько возможных случайных ключей для данной возможной карты или карты будет меняться между вами случайным ключи), вы по сути должны создать или поддерживать массив / список ключей, из которых вы выбираете случайный ключ.
0 голосов
/ 23 февраля 2016

Я написал утилиту для извлечения случайной записи, ключа или значения из карты, набора записей или итератора.

Поскольку вы не можете и не должны иметь возможность определить размер итератора ( Guava может сделать это ), вам придется перегрузить метод randEntry(), чтобы принять размер, который должен быть длиной записей.

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 голосов
/ 30 мая 2009

Я действительно не знаю, почему вы хотите это сделать ... но если это поможет, я создал RandomMap, который автоматически рандомизирует значения при вызове values ​​(), тогда следующее запускаемое демонстрационное приложение может сделать работа ...

  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 голосов
/ 30 мая 2009

Вот пример того, как использовать подход массива, описанный Питером Стуифзандом, также через values() -метод:

// 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) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...