有没有办法在Java中随机获取HashMap的值?

时间:2009-05-30 11:07:34

标签: java collections hashmap

有没有办法在Java中随机获取HashMap的值?

14 个答案:

答案 0 :(得分:50)

这有效:

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

答案 1 :(得分:30)

由于要求只要求HashMap中的随机值,这就是方法:

  1. HashMap有一个values方法,可以在地图中返回Collection个值。
  2. Collection用于创建List
  3. size方法用于查找List的大小,Random.nextInt方法使用该方法获取List的随机索引。
  4. 最后,使用随机索引从List get方法检索该值。
  5. 实现:

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

    关于这种方法的好处是所有方法都是generic - 不需要进行类型转换。

答案 2 :(得分:10)

如果您需要从地图中绘制更多的值而不重复任何元素,您可以将地图放入List中,然后将其随机播放。

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

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

答案 3 :(得分:3)

生成介于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)];

我不确定如何做随机数。

答案 4 :(得分:1)

一个好的答案在很大程度上取决于具体情况,特别是你需要为给定地图获取一个随机密钥的频率(N.B.无论你采用密钥还是值,技术基本相同)。

  • 如果您需要各种随机密钥 来自给定的地图,没有地图 在获得之间改变 随机密钥,然后在迭代时使用 random sampling method 通过钥匙组。实际上是什么 你做的是迭代集合 由keySet()返回,并在每个上 项目计算概率 考虑到如何,想要拿走那把钥匙 许多你需要整体和 你到目前为止的数字。然后 生成一个随机数,看看是否 这个数字低于 可能性。 (N.B. 此方法将始终有效,即使您只需要1个密钥;在这种情况下,它不一定是最有效的方式。)
  • HashMap中的键是有效的 已经伪随机顺序了。在一个 只有的极端情况 曾经需要一个随机密钥 给出可能的地图,你甚至可以 拉出的第一个元素 的keySet()即可。
  • 其他情况(您要么在哪里) 需要多个可能的随机密钥 对于给定的可能地图或地图 你会随意改变 键),你基本上必须 创建或维护您选择的键的数组/列表 随机密钥。

答案 5 :(得分:1)

将其转换为数组,然后在热路径中获取值太慢。

所以得到集合(键或键值集)并执行以下操作:

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

答案 6 :(得分:0)

以下是如何使用Peter Stuifzand描述的数组方法的示例,也是通过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) );

答案 7 :(得分:0)

我真的不知道你为什么要这样做...但如果它有帮助,我创建了一个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;
      }

  }

答案 8 :(得分:0)

通常你不是真的想要一个随机值,而只是任何值,然后这样做很好:

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

答案 9 :(得分:0)

我编写了一个实用程序来从地图,条目集或迭代器中检索随机条目,键或值。

由于您不能也不应该能够计算出迭代器(Guava can do this)的大小,您必须重载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();
    }
}

答案 10 :(得分:0)

如果您对O(n)的时间复杂度感到满意,则可以使用values()values().toArray()之类的方法,但是如果您寻找常量O(1) getRandom()的一种操作一个很好的选择是使用自定义数据结构。可以将ArrayListHashMap组合起来,以O(1)insert()remove()的时间获得getRandom()的时间。这是一个示例实现:

class RandomizedSet {
    List<Integer> nums = new ArrayList<>();
    Map<Integer, Integer> valToIdx = new HashMap<>();
    Random rand = new Random();

    public RandomizedSet() { }

    /**
     * Inserts a value to the set. Returns true if the set did not already contain
     * the specified element.
     */
    public boolean insert(int val) {
        if (!valToIdx.containsKey(val)) {
            valToIdx.put(val, nums.size());
            nums.add(val);
            return true;
        }
        return false;
    }

    /**
     * Removes a value from the set. Returns true if the set contained the specified
     * element.
     */
    public boolean remove(int val) {
        if (valToIdx.containsKey(val)) {
            int idx = valToIdx.get(val);
            int lastVal = nums.get(nums.size() - 1);

            nums.set(idx, lastVal);
            valToIdx.put(lastVal, idx);

            nums.remove(nums.size() - 1);
            valToIdx.remove(val);
            return true;
        }
        return false;
    }

    /** Get a random element from the set. */
    public int getRandom() {
        return nums.get(rand.nextInt(nums.size()));
    }
}

这个想法来自thisleetcode.com问题。

答案 11 :(得分:0)

如果您使用的是Java 8,则可以在一个不错的解决方案中使用findAny函数:

MyEntityClass myRandomlyPickedObject = myHashMap.values().stream().findAny();

答案 12 :(得分:-1)

这取决于你的密钥是什么 - hashmap的性质不允许这很容易发生。

我能想到的最好的方法是选择一个介于1和hashmap大小之间的随机数,然后开始迭代它,保持计数 - 当count等于您选择的随机数,即随机数。

答案 13 :(得分:-1)

这是一本来自Objects First with Java的练习。它如下所示.pickDefaultResponse()使用ArrayList生成一个响应并获取一个随机生成的整数并将其用作ArrayList的索引。这但是我想要克服的是填写两个列表。这里HashMap实例responseMap以及ArrayList实例defaultResponses都必须单独填写。

import java.util.HashMap;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

/**
 * The responder class represents a response generator object.
 * It is used to generate an automatic response, based on specified input.
 * Input is presented to the responder as a set of words, and based on those
 * words the responder will generate a String that represents the response.
 *
 * Internally, the reponder uses a HashMap to associate words with response
 * strings and a list of default responses. If any of the input words is found
 * in the HashMap, the corresponding response is returned. If none of the input
 * words is recognized, one of the default responses is randomly chosen.
 * 
 * @version    1.0
 * @author     Michael Kolling and David J. Barnes
 */
public class Responder
{
    // Used to map key words to responses.
    private HashMap<String, String> responseMap;
    // Default responses to use if we don't recognise a word.
    private ArrayList<String> defaultResponses;
    private Random randomGenerator;

    /**
     * Construct a Responder
     */
    public Responder()
    {
        responseMap = new HashMap<String, String>();
        defaultResponses = new ArrayList<String>();
        fillResponseMap();
        fillDefaultResponses();
        randomGenerator = new Random();
    }

    /**
     * Generate a response from a given set of input words.
     * 
     * @param words  A set of words entered by the user
     * @return       A string that should be displayed as the response
     */
    public String generateResponse(HashSet<String> words)
    {
        Iterator<String> it = words.iterator();
        while(it.hasNext()) {
            String word = it.next();
            String response = responseMap.get(word);
            if(response != null) {
                return response;
            }
        }
        // If we get here, none of the words from the input line was recognized.
        // In this case we pick one of our default responses (what we say when
        // we cannot think of anything else to say...)
        return **pickDefaultResponse();**
    }

    /**
     * Enter all the known keywords and their associated responses
     * into our response map.
     */
    private void fillResponseMap()
    {
        responseMap.put("crash", 
                        "Well, it never crashes on our system. It must have something\n" +
                        "to do with your system. Tell me more about your configuration.");
        responseMap.put("crashes", 
                        "Well, it never crashes on our system. It must have something\n" +
                        "to do with your system. Tell me more about your configuration.");
        responseMap.put("slow", 
                        "I think this has to do with your hardware. Upgrading your processor\n" +
                        "should solve all performance problems. Have you got a problem with\n" +
                        "our software?");
        responseMap.put("performance", 
                        "Performance was quite adequate in all our tests. Are you running\n" +
                        "any other processes in the background?");
        responseMap.put("bug", 
                        "Well, you know, all software has some bugs. But our software engineers\n" +
                        "are working very hard to fix them. Can you describe the problem a bit\n" +
                        "further?");
        responseMap.put("buggy", 
                        "Well, you know, all software has some bugs. But our software engineers\n" +
                        "are working very hard to fix them. Can you describe the problem a bit\n" +
                        "further?");
        responseMap.put("windows", 
                        "This is a known bug to do with the Windows operating system. Please\n" +
                        "report it to Microsoft. There is nothing we can do about this.");
        responseMap.put("macintosh", 
                        "This is a known bug to do with the Mac operating system. Please\n" +
                        "report it to Apple. There is nothing we can do about this.");
        responseMap.put("expensive", 
                        "The cost of our product is quite competitive. Have you looked around\n" +
                        "and really compared our features?");
        responseMap.put("installation", 
                        "The installation is really quite straight forward. We have tons of\n" +
                        "wizards that do all the work for you. Have you read the installation\n" +
                        "instructions?");
        responseMap.put("memory", 
                        "If you read the system requirements carefully, you will see that the\n" +
                        "specified memory requirements are 1.5 giga byte. You really should\n" +
                        "upgrade your memory. Anything else you want to know?");
        responseMap.put("linux", 
                        "We take Linux support very seriously. But there are some problems.\n" +
                        "Most have to do with incompatible glibc versions. Can you be a bit\n" +
                        "more precise?");
        responseMap.put("bluej", 
                        "Ahhh, BlueJ, yes. We tried to buy out those guys long ago, but\n" +
                        "they simply won't sell... Stubborn people they are. Nothing we can\n" +
                        "do about it, I'm afraid.");
    }

    /**
     * Build up a list of default responses from which we can pick one
     * if we don't know what else to say.
     */
    private void fillDefaultResponses()
    {
        defaultResponses.add("That sounds odd. Could you describe that problem in more detail?");
        defaultResponses.add("No other customer has ever complained about this before. \n" +
                             "What is your system configuration?");
        defaultResponses.add("That sounds interesting. Tell me more...");
        defaultResponses.add("I need a bit more information on that.");
        defaultResponses.add("Have you checked that you do not have a dll conflict?");
        defaultResponses.add("That is explained in the manual. Have you read the manual?");
        defaultResponses.add("Your description is a bit wishy-washy. Have you got an expert\n" +
                             "there with you who could describe this more precisely?");
        defaultResponses.add("That's not a bug, it's a feature!");
        defaultResponses.add("Could you elaborate on that?");
    }

    /**
     * Randomly select and return one of the default responses.
     * @return     A random default response
     */
    private String **pickDefaultResponse()**
    {
        // Pick a random number for the index in the default response list.
        // The number will be between 0 (inclusive) and the size of the list (exclusive).
        int index = randomGenerator.nextInt(defaultResponses.size());
        return defaultResponses.get(index);
    }
}