Случайная запись из словаря

Если вы передаете переменную в функцию, она оценивается и выдает ошибку, поскольку такой переменной нет. Напротив, в вашем базовом представлении вы обращаетесь к свойству объекта объекта, который будет всегда работать (и возвращать значение undefined, если свойства с таким именем не существует).

Вместо этого вам придется использовать оператор typeof, который будет работать даже для необъявленных переменных (посмотрите на переменную === undefined против переменной typeof === & quot; undefined & quot; и JavaScript проверяет, существует ли переменная (определена / инициализирована) ):


Чтобы использовать _.isUndefined в вашем шаблоне, вам нужно сделать значение явно доступным в шаблоне. Из документов :

По умолчанию template помещает значения из ваших данных в локальную область с помощью оператора with. Однако вы можете указать одно имя переменной с настройкой variable. Это может значительно повысить скорость, с которой шаблон может отображаться.

_.template("Using 'with': <%= data.answer %>", {answer: 'no'}, {variable: 'data'});
=> "Using 'with': no"

Таким образом, вы можете написать шаблоны так:

 <% if (!_.isUndefined(data.libraryPreps)) { %> …
 <% if ("libraryPreps" in data) { %> …

50
задан Lyyn 30 January 2018 в 03:54
поделиться

8 ответов

Обновлено, чтобы использовать дженерики, работать еще быстрее и с объяснением, почему этот вариант работает быстрее.

Этот ответ аналогичен другим ответам, но, поскольку вы сказали, что вам нужен "a количество случайных элементов », это будет более производительным:

public IEnumerable<TValue> RandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Random rand = new Random();
    List<TValue> values = Enumerable.ToList(dict.Values);
    int size = dict.Count;
    while(true)
    {
        yield return values[rand.Next(size)];
    }
}

Вы можете использовать этот метод следующим образом:

Dictionary<string, object> dict = GetDictionary();
foreach (object value in RandomValues(dict).Take(10))
{
    Console.WriteLine(value);
}

У него есть улучшения производительности по сравнению с другими ответами (включая ответ yshuditelu).

  1. Он не должен создавать новая коллекция всех элементов словаря каждый раз, когда вы хотите получить новое случайное значение. Это действительно большое дело, если в вашем словаре много элементов.
  2. Нет необходимости выполнять поиск на основе ключа словаря каждый раз, когда вы выбираете случайное значение. Не такая большая проблема, как №1, но все равно в два раза быстрее.
42
ответ дан 7 November 2019 в 10:39
поделиться

Если вы используете .net 3.5, Enumerable имеет метод расширения ElementAt , который позволит вам делать:

return dict.ElementAt(rand.Next(0, dict.Count)).Value;
49
ответ дан 7 November 2019 в 10:39
поделиться

Из вашего словаря ...

Dictionary<string, int> dict = new Dictionary<string, object>()

вы можете создать полный список ключей ...

List<string> keyList = new List<string>(dict.Keys);

, а затем выбрать случайный ключ из вашего списка.

Random rand = new Random();
string randomKey = keyList[rand.Next(keyList.Count)];

Затем просто верните случайный объект , соответствующий этому ключу.

return dict[randomKey];
17
ответ дан 7 November 2019 в 10:39
поделиться

Что-то вроде:

Random rand = new Random();
Dictionary dict = GetDictionary();
var k = dict.Keys.ToList()[rand.Next(dict.Count)];
return dict[k];
3
ответ дан 7 November 2019 в 10:39
поделиться

Это будет не очень быстро, но должно работать:

Random rand = new Random();
Dictionary dict = GetDictionary();
return dict.Skip(rand.Next(dict.Count)).First().Value;
2
ответ дан 7 November 2019 в 10:39
поделиться

Я считаю, что единственный способ - сначала создать отдельный список KeyValuePairs.

0
ответ дан 7 November 2019 в 10:39
поделиться

Другой мой ответ на этот вопрос верен и может быть полезен во многих случаях, например, при получении информации о броске с пользовательских кубиков (каждый бросок кубика является случайным, независимо от других кубиков). Однако ваши комментарии звучат так, будто вы надеетесь получить серию «уникальных» элементов из Словаря , что-то вроде раздачи карт из колоды. После того, как карта будет сдана, вы больше никогда не захотите видеть ту же карту, пока не перетасуетесь. В этом случае лучшая стратегия будет зависеть от того, что именно вы делаете.

Если вы получаете только несколько элементов из большого Словаря , тогда вы сможете адаптировать мой другой ответ, удаляя случайный элемент из списка каждый раз, когда извлекается новый. Вы' Я, вероятно, также захочу превратить этот список в LinkedList , потому что, хотя поиск элемента по его индексу будет медленнее, гораздо дешевле удалить элементы из его середины. Код для этого был бы немного более сложным, поэтому, если вы готовы пожертвовать производительностью ради простоты, вы можете просто сделать это:

public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    Random rand = new Random();
    Dictionary<TKey, TValue> values = new Dictionary<TKey, TValue>(dict);
    while(values.Count > 0)
    {
        TKey randomKey = values.Keys.ElementAt(rand.Next(0, values.Count));  // hat tip @yshuditelu 
        TValue randomValue = values[randomKey];
        values.Remove(randomKey);
        yield return randomValue;
    }
}

Если, с другой стороны, вы планируете вытащить значительное количество элементов из вашего словаря (т.е. раздайте больше, чем log (n) вашей «колоды»), вам будет лучше сначала перетасовать всю свою колоду, а затем вытащить ее сверху:

public IEnumerable<TValue> UniqueRandomValues<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
    // Put the values in random order
    Random rand = new Random();
    LinkedList<TValue> values = new LinkedList<TValue>(from v in dict.Values
                                                       orderby rand.Next()
                                                       select v);
    // Remove the values one at a time
    while(values.Count > 0)
    {
        yield return values.Last.Value;
        values.RemoveLast();
    }
}

Кредит принадлежит ookii .org для простого перетасовки кода. Если это все еще не совсем то, что вы искали, возможно, вы можете задать новый вопрос с более подробной информацией о том, что вы пытаетесь сделать.

12
ответ дан 7 November 2019 в 10:39
поделиться

Простым решением было бы использовать метод расширения ToList () и использовать индекс списка.

Если вам просто нужны значения или ключи (не пара ключ / значение) возвращают эти коллекции из словаря и также используют ToList () .

        Random rand = new Random();
        Dictionary<string, object> dict = GetDictionary();
        var k = dict.ToList()[rand.Next(dict.Count)];
        // var k = dict.Values.ToList()[rand.Next(dict.Count)];
        // var k = dict.Keys.ToList()[rand.Next(dict.Count)];

        Console.WriteLine("Random dict pair {0} = {1}", k.Key, k.Value);
1
ответ дан 7 November 2019 в 10:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: