2013-12-24 3 views
2

Скажем, я хочу последовательность из 10 цифр, и у меня есть функция, которая производит номера по запросу:Как преобразовать цикл for (не foreach) в Linq?

var s = new List<int>(); 
for (var i=0; i<10; i++) { 
    s.Add(Magically_generate_a_very_special_number()); 
} 

обычный способ решения этой проблемы. Однако, допустим, я хочу использовать LINQ. Я уже могу (не будем игнорировать различия между типами):

var s = Enumerable.Range(0, 10).Select(i => MathNet.Numerics.Statistics.DescriptiveStatistics()) 

Это почти достаточно для меня. Тем не менее, меня беспокоит, что сначала нужно указать диапазон целых чисел - это лишний шаг, так как я все равно отказываюсь от значения. Можно ли сделать что-то вроде следующего?

var s = Enumerable.ObjectMaker(Magically_generate_a_very_special_number).Take(10); 

Кажется, что Enumerable.Repeat почти делает то, что я хочу, но он принимает результат функции я даю его, а затем дублирует, вместо того, чтобы повторно оценить функцию.

Кстати, источником вдохновения для этого вопроса был метод Math.Net IContinuousDistribution.Samples. Его тело выглядит следующим образом:

while (true) 
{ 
    yield return Generate_a_random_number(); 
} 

Так что вы можете получить последовательность выборок из распределения с myDistribution.Samples.Take. В принципе, я мог бы просто написать свой собственный метод для создания итератора таким же образом, но мне интересно, существует ли он уже существующий.

+0

Может быть, я действительно из линии здесь, но ИМХО, цель LINQ заключается в уменьшении количества строк кода и выбрать определенные элементы из перечислимого на основе определенных условий или нет. Он не предназначен для создания новых объектов. – danish

+0

Нет, это вполне разумный комментарий. Однако, в некоторых случаях, LINQ легче читать (в моих личных проектах). – Superbest

ответ

2

Вы можете попробовать использовать метод Еогеасп:

Enumerable.Take(10).ToList().Foreach(Magically_generate_a_very_special_number); 

Даунсайд IMHO является то, что вы должны сделать ToList между ними.

редактировать неправильно истолковывать вопрос, так nvmd :)

+0

На самом деле я имел в виду 'foreach' цикл, а не' Foreach' метод. Ваш код почти то, что я хочу ... Но почему мне нужно называть 'ToList'? – Superbest

+0

@Superbest, потому что метод расширения 'Foreach' определен в' List ', а не' IEnumerable '. – Vache

+1

@Vache 'ForEach' не является ни методом расширения, ни методом LINQ, несмотря на то, что многие считают. Это метод «List », относящийся к .NET 2.0. –

1

Вы можете создать последовательность из 10 делегатов метода ссылающихся вашего метода Magically_generate_a_very_special_number, а затем вызывать их последовательно.

var s = Enumerable.Repeat<Func<int>>(generate, 10).Select(f => f()); 
0

Я согласен с датском: Я думаю, что пытается сделать это в базе LINQ является уродливее и труднее читать, чем просто делать это в цикле. Кажется, чтобы победить цель linq.

Это, может быть, вы можете сделать метод расширения. До тех пор пока ваша Magically_generate_a_very_special_number функция не требует параметров, то, как это должно делать то, что вы после:

public static void Fill<T>(this IList<T> list, int repeat, Func<T> fn) { 
    for (int i = 0; i < repeat; i++) list.Add(fn()); 
} 

Затем используйте так:

s.Fill(10, Magically_generate_a_very_special_number); 
0

Мы можем создать новый метод для создания N объектов путем вызова функции генерации N раз, что следует за общую картину методов LINQ, так что у вас есть то, что соответствует вашим потребностям:

public static IEnumerable<T> Generate<T>(Func<T> generator, int count) 
{ 
    for (int i = 0; i < count; i++) 
     yield return generator(); 
} 

И теперь вы можете предписанием е:

var numbers = Generate(Magically_generate_a_very_special_number, 10); 
1

Я не думаю, что, как ваш Enumerable.ObjectMaker существует как удобная часть LINQ, но вы можете сделать один раз, как это.

public static IEnumerable<T> ObjectMaker<T>(Func<T> generator) { 
    while (true) 
     yield return generator(); 
} 
var s = ObjectMaker(MagicallyGenerateVerySpecialNumber).Take(10); 
Смежные вопросы