Выбор случайных ключей и наборов значений из карты в Java - PullRequest
30 голосов
/ 29 марта 2012

Я хочу получить случайные ключи и их соответствующие значения с карты.Идея состоит в том, что генератор случайных чисел выберет ключ и отобразит это значение.Сложность в том, что и ключ, и значение будут строками, например myMap.put("Geddy", "Lee").

Ответы [ 8 ]

48 голосов
/ 29 марта 2012
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);
4 голосов
/ 29 марта 2012

Этот вопрос должен быть вам полезен Есть ли способ получить значение HashMap случайным образом в Java? , а также этот Выбор случайного элемента из набора , потому что HashMap поддерживается HashSet. Это будет либо O(n) время и постоянное пространство, либо O(n) дополнительное пространство и постоянное время.

3 голосов
/ 29 марта 2012

Если вы не возражаете против потраченного впустую пространства, один из подходов состоит в том, чтобы отдельно хранить List всех ключей, которые находятся в Map. Для лучшей производительности вам понадобится List с хорошей производительностью произвольного доступа (например, ArrayList). Затем просто получите случайное число от 0 (включительно) до list.size() (исключая), вытащите ключ с этим индексом и посмотрите на него.

Random rand = something
int randIndex = rand.nextInt(list.size());
K key = list.get(randIndex);
V value = map.get(key);

Этот подход также означает, что добавление пары ключ-значение намного дешевле, чем ее удаление. Чтобы добавить пару ключ-значение, вы должны проверить, есть ли ключ на карте (если ваши значения могут быть нулевыми, вам придется отдельно вызывать map.containsKey; если нет, вы можете просто добавить ключ- пара значений и посмотрите, является ли «старое значение», которое он возвращает, null). Если ключ уже находится на карте, список не изменяется, но если нет, вы добавляете ключ в список (операция O (1) большинство списков.) Однако для удаления пары ключ-значение требуется операция O (N) для удаления ключа из списка.

Если пространство представляет большую проблему, но производительность ниже, вы также можете получить Iterator над набором записей карты (Map.entrySet()) и пропустить randIndex записей перед возвратом нужного. Но это будет операция O (N), которая как бы побеждает всю точку карты.

Наконец, вы можете просто получить набор входных данных toArray() и случайным образом внести в него индекс. Это проще, хотя и менее эффективно.

2 голосов
/ 29 марта 2015

если ваши ключи целочисленные или что-то сопоставимое, вы можете использовать TreeMap для этого.

TreeMap<Integer, Integer> treeMap = new TreeMap<>();
int key = RandomUtils.ranInt(treeMap.lastKey());
int value = treeMap.ceilingKey(key);
1 голос
/ 31 марта 2012

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

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 голос
/ 29 марта 2012

Я бы скопировал карту в массив и выбрал бы произвольную запись.Это позволяет избежать необходимости поиска значения из ключа.

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

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

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);
}
0 голосов
/ 28 мая 2016
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 голосов
/ 29 марта 2012

Давненько не играл с java, но разве keySet () не дает вам список, который вы можете выбрать из числового индекса? Я думаю, что вы можете выбрать случайное число и выбрать его из набора ключей myMap, а затем выбрать соответствующее значение из myMap. Сейчас не могу проверить это, но мне кажется, что это возможно!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...