Если вы передаете переменную в функцию, она оценивается и выдает ошибку, поскольку такой переменной нет. Напротив, в вашем базовом представлении вы обращаетесь к свойству объекта объекта, который будет всегда работать (и возвращать значение 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) { %> …
Обновлено, чтобы использовать дженерики, работать еще быстрее и с объяснением, почему этот вариант работает быстрее.
Этот ответ аналогичен другим ответам, но, поскольку вы сказали, что вам нужен "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).
Если вы используете .net 3.5, Enumerable имеет метод расширения ElementAt , который позволит вам делать:
return dict.ElementAt(rand.Next(0, dict.Count)).Value;
Из вашего словаря ...
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];
Что-то вроде:
Random rand = new Random();
Dictionary dict = GetDictionary();
var k = dict.Keys.ToList()[rand.Next(dict.Count)];
return dict[k];
Это будет не очень быстро, но должно работать:
Random rand = new Random();
Dictionary dict = GetDictionary();
return dict.Skip(rand.Next(dict.Count)).First().Value;
Я считаю, что единственный способ - сначала создать отдельный список KeyValuePairs.
Другой мой ответ на этот вопрос верен и может быть полезен во многих случаях, например, при получении информации о броске с пользовательских кубиков (каждый бросок кубика является случайным, независимо от других кубиков). Однако ваши комментарии звучат так, будто вы надеетесь получить серию «уникальных» элементов из Словаря
, что-то вроде раздачи карт из колоды. После того, как карта будет сдана, вы больше никогда не захотите видеть ту же карту, пока не перетасуетесь. В этом случае лучшая стратегия будет зависеть от того, что именно вы делаете.
Если вы получаете только несколько элементов из большого Словаря
, тогда вы сможете адаптировать мой другой ответ, удаляя случайный элемент из списка каждый раз, когда извлекается новый. Вы' Я, вероятно, также захочу превратить этот список в 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 для простого перетасовки кода. Если это все еще не совсем то, что вы искали, возможно, вы можете задать новый вопрос с более подробной информацией о том, что вы пытаетесь сделать.
Простым решением было бы использовать метод расширения 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);