Алгоритм перебора на LINQ
От: Maru  
Дата: 03.02.14 09:39
Оценка:
Есть алфавит в виде произвольного массива 'a'...'z' и выходная длина N.
Возможно ли написать алгоритм перебора ("a..aa", "a..ab", .. , "z..zz") в виде чистого linq выражения без использования явных циклов и дополнительных контейнеров, которое будет лениво выводить одно за другим все значения?

string[] ss = new string[] {"a", "b", "c"};
int N = 3;

var result = from ss select ?;

foreach (var x in result)
{
Console.WriteLine(x); // "aaa" — "zzz"
}

Чувствую, что тут нужен SelectMany, но пока данный орешек не поддается.
Re: Алгоритм перебора на LINQ
От: Sinix  
Дата: 03.02.14 09:51
Оценка: +1
Здравствуйте, Maru, Вы писали:

M>Чувствую, что тут нужен SelectMany, но пока данный орешек не поддается.

Решение в лоб:
        static void Main(string[] args)
        {
            string[] ss = new string[] { "a", "b", "c" };
            int N = 3;
            var result = ss.AsEnumerable();
            for (int i = 1; i < N; i++)
            {
                result = result.SelectMany(s => ss.Select(s1 => s + s1));
            }
            foreach (var item in result)
            {
                Console.WriteLine(item);
            }
            Console.ReadKey();
        }

У Липперта была целая серия статей на связанную тему, вот первая. Я их скорее пролистал, чем прочитал, так что сходу не вспомню есть ли там готовое решение.
Re: Алгоритм перебора на LINQ
От: samius Япония http://sams-tricks.blogspot.com
Дата: 03.02.14 10:52
Оценка:
Здравствуйте, Maru, Вы писали:

M>Есть алфавит в виде произвольного массива 'a'...'z' и выходная длина N.

M>Возможно ли написать алгоритм перебора ("a..aa", "a..ab", .. , "z..zz") в виде чистого linq выражения без использования явных циклов и дополнительных контейнеров, которое будет лениво выводить одно за другим все значения?
Используй рекурсию, Люк!
Re[2]: Алгоритм перебора на LINQ
От: Аноним  
Дата: 03.02.14 13:37
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Решение в лоб:

S>
S>        static void Main(string[] args)
S>        {
S>            string[] ss = new string[] { "a", "b", "c" };
S>            int N = 3;
S>            var result = ss.AsEnumerable();
S>            for (int i = 1; i < N; i++)
S>            {
S>                result = result.SelectMany(s => ss.Select(s1 => s + s1));
S>            }
S>            foreach (var item in result)
S>            {
S>                Console.WriteLine(item);
S>            }
S>            Console.ReadKey();
S>        }
S>

S>У Липперта была целая серия статей на связанную тему, вот первая. Я их скорее пролистал, чем прочитал, так что сходу не вспомню есть ли там готовое решение.

Такое решение более-менее очевидно, спасибо. Мне хочется, чтобы не было промежуточных результатов, и чтобы было полностью ленивое решение.
Re: Алгоритм перебора на LINQ
От: Spiceman  
Дата: 04.02.14 09:28
Оценка: +1
Здравствуйте, Maru, Вы писали:

M>Чувствую, что тут нужен SelectMany, но пока данный орешек не поддается.


Без SelectMany:

        static void Main(string[] args)
        {
            string[] ss = new string[] { "a", "b", "c" };
            int N = 3;
            var result = Enumerable.Repeat(0, N-1)
                .Aggregate(ss.AsEnumerable(), (res, i) => res.Join(ss, a => 0, a => 0, (a, b) => a + b));
            foreach (var s in result)
            {
                Console.WriteLine(s);
            }
            Console.ReadKey();
        }


Цикл в решении от Sinix так же можно переделать через Enumerable.Repeat(0, N-1).
Re[3]: Алгоритм перебора на LINQ
От: Spiceman  
Дата: 04.02.14 09:33
Оценка: +1
Здравствуйте, Аноним, Вы писали:

А>Такое решение более-менее очевидно, спасибо. Мне хочется, чтобы не было промежуточных результатов, и чтобы было полностью ленивое решение.


А там и нет промежуточных результатов. Выражение начинает вычисляться только в момент foreach. Так что, с циклом решение тоже ленивое, в нем нет вычислений, а только построение выражения.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.