Хотя Loop с назначением в C # Linq

Я хотел бы присвоить переменную vStreamID случайным числом. Этот номер должен быть вновь сгенерирован до тех пор, пока мой словарь md_StreamDict содержит сгенерированный номер.

Длинная версия:

vStreamID = (new Random()).Next(1000, 9999).ToString();
while (md_StreamDict.ContainsKey(vStreamID)) {
    vStreamID = (new Random()).Next(1000, 9999).ToString();
}

Я хотел бы увидеть что-то типа LINQ

md_StreamDict.ContainsKey(vStreamID)
    .while( x => x = (new Random())
    .Next(1000, 9999)
    .ToString();

Я знаю, что пример выше - бананы. Но я был бы счастлив, если бы был реальный способ добиться этого. И нет, мы снова не начинаем обычное обсуждение читаемости. ;)

4
Я думаю, что Neurodefect нуждается в новом предмете в своем словаре, где ключ случайный и не существует в словаре. Почему linq, dunno ..
добавлено автор Ralf de Kleine, источник
Никогда не вызывайте new Random() много раз. Просто создайте один экземпляр Random и повторите использование этого генератора случайных чисел. В противном случае вы можете создать идентичные экземпляры Random (время, возможно, не изменилось с одного экземпляра на следующий), а затем .Next (...) даст тот же число для каждого экземпляра Random .
добавлено автор Jeppe Stig Nielsen, источник
Если вы хотите, чтобы 9999 был возможным результатом, используйте .Next (1000, 10000) .
добавлено автор Jeppe Stig Nielsen, источник
Так что вам просто нужно число в определенном диапазоне, и этот номер не должен быть уже в словаре, зачем вам нужен Random?
добавлено автор sll, источник
Даже длинная версия может быть короче, если вы использовали do {} while (); :-)
добавлено автор fero, источник

5 ответы

Вам нужен способ генерации бесконечного перечислимого для потоковой передачи случайных чисел. Вы можете аппроксимировать, используя Enumerable.Range (0, int.MaxValue ):

var rand = new Random();
var r = Enumerable.Range(0, int.MaxValue)
    .Select(s => rand.Next(1000, 9999))
    .SkipWhile(s => md_StreamDict.ContainsKey(s.ToString()))
    .First();

Тогда r будет содержать новое значение ключа, не содержащееся в словаре.

4
добавлено
Это не создаст бесконечный список, и вы не можете быть на 100% уверены, что он будет содержать все значения от 1000 до9999. Вы должны либо выполнить while (true), чтобы получить random.Next() , либо создать список int в этом диапазоне и перетасовать.
добавлено автор Jon B, источник
@JonB: Это правильно. Хотя я думаю, что если вы добрались до 4294967296 , не найдя недостающий ключ, вы можете написать книгу о статистических аномалиях. Не говоря уже о том, что если ваш словарь будет полным, вы будете долго ждать, чтобы найти одну дыру любым способом.
добавлено автор mellamokb, источник
@ OlivierJacot-Descombes: Хорошая точка. Обновлено. Я просто слепо копировал оригинальную логику OP в формате LINQ.
добавлено автор mellamokb, источник
Не создавайте экземпляр Random в цикле! См. stackoverflow.com/a/3053811/880990
добавлено автор Olivier Jacot-Descombes, источник

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

Enumerable.Range(1000, 9999)
          .Where(n => !dict.ContainsKey(n))
          .FirstOrDefault();
4
добавлено
добавлено автор SWeko, источник
Что такое диапазон ?
добавлено автор mellamokb, источник
@Neurodefekt Это всегда дает самый низкий (четырехзначный или менее 10999) номер не в dict .
добавлено автор Jeppe Stig Nielsen, источник
Вы даже можете сказать .FirstOrDefault (n =>! Dict.ContainsKey (n)) . В любом случае, если dict содержит все ключи от 1000 до 10998, это возвращает 0. К сожалению, вы поняли, что Range (1000, 9999) дает числа от 1000 до 10998 ?
добавлено автор Jeppe Stig Nielsen, источник
@sll: Позвольте мне быть более явным: (new Random ()). Далее (1000, 9999) соответствует в диапазоне от Enumerable.Range (1000, 8999) , поэтому ваш ответ ошибся. Если исходный плакат действительно означал (новый Random ()). Далее (1000, 10000) , это будет Enumerable.Range (1000, 9000) .
добавлено автор Jeppe Stig Nielsen, источник
Вы правы, «магические числа» ошибочны
добавлено автор sll, источник
Извините, исправлено
добавлено автор sll, источник
Работает и выглядит круто! Спасибо. :)
добавлено автор Neurodefekt, источник

Вот некоторые бананы:

Вы можете создать IEnumerable, который генерирует случайные числа, например:

public class RandomList : IEnumerable
{
    public IEnumerator GetEnumerator()
    {
        Random r = new Random();

        while (true)
            yield return r.Next(1000, 9999);
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

Тогда вы можете сделать:

// I guess one could implement a seed constructor, if one was so inclined
RandomList rl = new RandomList(); 

int vStreamID = rl.SkipWhile(i => md_StreamDict.ContainsKey(i)).First();
3
добавлено

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

var r = new Random();

do {
    vStreamID = r.Next(1000, 9999).ToString();
} while (md_StreamDict.ContainsKey(vStreamID));
2
добавлено

Один из подходов заключался бы в использовании доходности для возврата значений

 private static Random rand = new Random();

    private static void Test()
    {
        Dictionary values = new Dictionary();
        string vStreamId = GetNewValues().Where(x => !values.ContainsKey(x)).First();
    }

    public static IEnumerable GetNewValues()
    {
        While(true)
        {
           yield return rand.Next(1000, 9999).ToString();
        }
    }

Обратите внимание: если вы создаете новый Random в каждом цикле, вы получите одно и то же значение каждый раз, когда оно основано на системных часах.

2
добавлено
Попробуйте запустить его. Получить новые значения даст одно случайное число, а затем вернется. Вы должны сделать while (true) return return ...
добавлено автор Jon B, источник
Это даст единую ценность.
добавлено автор Jon B, источник
Не уверен, что я понимаю вас, Джон, функция GetNewValues ​​() возвращает новое значение для каждого вызова, а оператор LINQ будет выбирать первый, который не находится в словаре?
добавлено автор David McNee, источник
Ooooh ...... palm => face =) вы правы ... ответ обновлен
добавлено автор David McNee, источник
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot