3

I wrote a function that accepts (Func & int N) and repeats the Func N times and returns a result.

public IEnumerable<T> MyFunction(Func<T, T> function, int iteration)
{

}

Is there any way to repeat a function using Enumerable.Repeat?

public IEnumerable<T> MyFunction(Func<T, T> function, int iteration)
{
    yield return Enumerable.Repeat<T>(function.Invoke(), iteration);
}

I tried to run the code above, but the function runs once.

Saleh Bagheri
  • 424
  • 4
  • 19
  • In a word, no. `Repeat` is not meant to repeat a function call; it is meant to repeat a value. Just use a loop like any sane programmer ;). – Heretic Monkey May 25 '19 at 20:16
  • We can repeat an `Action` also. Is `Action` a value? @HereticMonkey – Saleh Bagheri May 25 '19 at 20:19
  • Can you show me documentation that `Enumerable.Repeat` can run an `Action` a number of times? The only [documentation I can find says it returns an enumerable of some kind of value a specified number of times](https://stackoverflow.com/q/15171294/215552) – Heretic Monkey May 25 '19 at 20:22
  • Use this : `Enumerable.Repeat(() => { Console.WriteLine("Hello World"); },10).ToList().ForEach(f => f.Invoke());` @HereticMonkey – Saleh Bagheri May 25 '19 at 20:26
  • 1
    That's not executing the action; that defining 10 actions that are ready to be invoked (an are, *later*, in your `ForEach`) (and you shouldn't need the `ToList` in there either) – Heretic Monkey May 25 '19 at 20:28
  • So, Is there any way to repeat a func like that? @HereticMonkey – Saleh Bagheri May 25 '19 at 20:30
  • 1
    [Edit] your question with a realistic way in which you'll be using this. Right now it doesn't look very practical; a loop would do the same thing in less code that is more meaningful to later readers.. – Heretic Monkey May 25 '19 at 20:34
  • 4
    You could construct something weird that repeated a function using `Repeat`, so technically the answer is yes. `Repeat` repeats anything. But it would be oddly convoluted. The next developer would be confused, possibly rewrite it using a loop, and then worry that there was something more complicated going on and they just missed it. Then, when they realize that they didn't miss anything, they'll get this sinking feeling and think, "Oh, no, what else am I going to find in here?" – Scott Hannen May 25 '19 at 20:34

3 Answers3

4

Why not simply call the method in a loop:

for(int i = 0; i < iteration; i++)
    yield return function(myTInstance);

or in a Linq-statement:

return Enumerable.Range(0, iteration).Select(x => function(MyTInstance));
MakePeaceGreatAgain
  • 35,491
  • 6
  • 60
  • 111
  • Thanks, @HimBromBeere! But I'm looking for an elegant way to repeat a function. – Saleh Bagheri May 25 '19 at 20:33
  • 2
    @SalehBagheri I don´t get what you want. This code does exactly what you want: executing a method a number of times and aggregate all the methods return-values into a collection. – MakePeaceGreatAgain May 25 '19 at 20:35
  • @HimBromBeere I think he should learn what is a nail, what is a tool, what is return type, then start using hammers LINQ. Otherwise he will end up with a mess in his mind and become "copy and paste programmer" ;) – Kamil May 25 '19 at 21:03
2

There is a way, although I'm not sure what it proves.

static public IEnumerable<T> MyFunction<T>(Func<T> function, int iteration)
{
    return Enumerable.Repeat(function, iteration).Select( x => x() );
}

public static void Main()
{
    int n = 0;

    foreach (var i in MyFunction(() => n++, 10)) Console.WriteLine(i);
}

For some reason though it is more common to see people do it this way:

    return Enumerable.Range(0, iteration).Select( x => function() );

I see the latter construct on Stackoverflow all the time.

Output:

0
1
2
3
4
5
6
7
8
9
John Wu
  • 50,556
  • 8
  • 44
  • 80
  • @John-wu You are using LINQ and lambda expression to answer a question asked by someone who does not understand enumerators and yield keyword. The answer without LINQ and lambda would be easier to understand for novices. – Kamil May 25 '19 at 20:55
  • @Kamil, I asked only a question about repeating a function without using `For` or `ForEach` or other looping keywords. Do you have any Idea about it? If you don't, please do not judge my knowledge! – Saleh Bagheri May 26 '19 at 07:22
  • 1
    @Kamil I believe this answer is helpful because it demonstrates a correct, idiomatic, and what is probably the only use for `Enumerable.Repeat()`, which is to combine it with LINQ to generate useful sequences. I don't know what else I'd use it for, honestly. – John Wu May 26 '19 at 10:50
  • No-one here is judging anyone. But you need to understand that LINQ internally calls `foreach` anyway, it just hides that from the caller. So the only difference between `myCollection.Select(x => ...)` and `foreach(var x in myCollection) ...` is the *syntax*. However both statements will do the exact same things. – MakePeaceGreatAgain Nov 28 '22 at 11:33
0
// this is wrong

public IEnumerable<T> MyFunction(Func<T, T> function, int iteration)
{
    yield return Enumerable.Repeat<T>(function.Invoke(), iteration);
}

you return whole IEnumerable collection returned by Repeat(...) in a single yield (pointless).

Another problem of your method is return type. If you want to return your Func objects you have to replace return type of your method from IEnumerable<T> to Func<T,T>.

Purpose of Enumerable.Repeat<T>(...) method is to create a collection with N instances of given object and return whole collection.

If you want to return objects in yields you have to return these objects one by one.

I think you need something like this: (for better understanding I'm not using LINQ and lambda expressions)

public Func<T,T> MyFunction(Func<T, T> function, int iteration)
{
    // create a collection with `N = interation` items
    IEnumerable<Func<T,T>> items = Enumerable.Repeat<T>(function.Invoke(), iteration);

    // return items
    foreach(Func<T,T> item in items)
    {
        yield return item;
    }
}
Kamil
  • 13,363
  • 24
  • 88
  • 183