33

I have a method which takes in N, the number of objects I want to create, and I need to return a list of N objects.

Currently I can do this with a simple loop:

    private static IEnumerable<MyObj> Create(int count, string foo)
    {
        var myList = new List<MyObj>();

        for (var i = 0; i < count; i++)
        {
            myList .Add(new MyObj
                {
                    bar = foo
                });
        }

        return myList;
    }

And I'm wondering if there is another way, maybe with LINQ to create this list.

I've tried:

    private static IEnumerable<MyObj> CreatePaxPriceTypes(int count, string foo)
    {
        var myList = new List<MyObj>(count);

        return myList.Select(x => x = new MyObj
            {
                bar = foo
            });

    }

But this does seem to populate my list.

I tried changing the select to a foreach but its the same deal.

I realized that the list has the capacity of count and LINQ is not finding any elements to iterate.

        myList.ForEach(x => x = new MyObj
        {
            bar = foo
        });

Is there a correct LINQ operator to use to get this to work? Or should I just stick with the loop?

EdmundYeung99
  • 2,461
  • 4
  • 27
  • 43
  • LINQ is a query tool, it shouldn't be used excessively for creation of objects – Sayse Aug 08 '13 at 09:34
  • 1
    Linq operators like `.Select()` are intended purely for querying sets and projecting them to the required forms; they're not meant to do anything that alters the original set. What you're trying to do with `.Select()` is not recommended, although it can be made to work. I'd stick with the loop. – anaximander Aug 08 '13 at 09:36
  • this might be of some value: http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx – default Aug 08 '13 at 09:39
  • if you want to spice it up you can use `yield return new MyObj(){ ... };` instead of saving the temporary list – default Aug 08 '13 at 09:47
  • Would not `MyObj[100].AsEnumerable()` work? – Wobbles Oct 17 '16 at 10:14

3 Answers3

73

You can use the Range to create a sequence:

return Enumerable.Range(0, count).Select(x => new MyObj { bar = foo });

If you want to create a List, you'd have to ToList it.

Mind you though, it's (arguably) a non-obvious solution, so don't throw out the iterative way of creating the list just yet.

Patryk Ćwiek
  • 14,078
  • 3
  • 55
  • 76
  • oh interesting, how about the Repeat method? does that do the same thing? or would it only create a single object, and creates a list of pointers to reference that one object? – EdmundYeung99 Aug 08 '13 at 09:58
  • 3
    In this particular case, it doesn't matter whether it's `Range` or `Repeat`, since you don't use the object in `Select`. What matters is that it generates a sequence with N elements, which you need to create exactly N new objects... – Patryk Ćwiek Aug 08 '13 at 10:16
7

You could create generic helper methods, like so:

// Func<int, T>: The int parameter will be the index of each element being created.

public static IEnumerable<T> CreateSequence<T>(Func<int, T> elementCreator, int count)
{
    if (elementCreator == null)
        throw new ArgumentNullException("elementCreator");

    for (int i = 0; i < count; ++i)
        yield return (elementCreator(i));
}

public static IEnumerable<T> CreateSequence<T>(Func<T> elementCreator, int count)
{
    if (elementCreator == null)
        throw new ArgumentNullException("elementCreator");

    for (int i = 0; i < count; ++i)
        yield return (elementCreator());
}

Then you could use them like this:

int count = 100;

var strList = CreateSequence(index => index.ToString(), count).ToList();

string foo = "foo";
var myList = CreateSequence(() => new MyObj{ Bar = foo }, count).ToList();
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
2

You can Use Enumerable.Repeat

IEnumerable<MyObject> listOfMyObjetcs = Enumerable.Repeat(CreateMyObject, numberOfObjects);

For more info read https://msdn.microsoft.com/en-us/library/bb348899(v=vs.110).aspx

Marc Cals
  • 2,963
  • 4
  • 30
  • 48
  • 1
    I'm afraid that this will generate a collection filled by a single value – Ilia Maskov Jun 07 '18 at 07:19
  • 1
    To clarify @IliaMaskov's comment: `Repeat` is useful for a **value**; e.g. to make a sequence of `0`s, but can't create independent **objects**, as requested in the question. To create a list of `0`s: `var myList = Enumerable.Repeat(0, count).ToList();`, where `count` is the number of elements to create. – ToolmakerSteve Oct 08 '21 at 14:39