Is there a way to fill a collection using a LINQ e

2019-02-15 06:02发布

问题:

One of the great things about LINQ is that allows you to get information that's related to a collection without having to manually write code to iterate through the collection. Is there a way to use LINQ to populate a collection, thus avoiding the need to write a loop?


For example, let's say I have the following code which works with a range of numbers from one to ten:

public static void LinqTest()
{
    List<int> intList = new List<int>();
    for (int i = 1; i <= 10; i++)     //  <==== I'm having to use a for loop
        intList.Add(i);               //        here to populate the List.
    int intSum = intList.Sum();
    int intSumOdds = intList.Where(x => x % 2 == 1).Sum();
    double intAverage = intList.Average();
    Console.WriteLine("Sum is {0}\tSum of Odds is {1}\tAverage is {2}", 
        intSum, intSumOdds, intAverage);
}

LINQ is already replacing the for loops that would be required to retrieve information about the data. I'm curious as if LINQ could be used to replace the for loop that populates data. Is there a way to use LINQ to replace the following two lines of code?

    for (int i = 1; i <= 10; i++)
        intList.Add(i);

回答1:

As the others have said, you can use Enumerable.Range(int, int) to generate a sequence of integers returned as IEnumerable<int>.

And while you can convert the result to a List<int> in the various ways that have been suggested already, you should only do that if you actually need a List<T>.

In this case, there is no need to do so. Your function could be rewritten as follows:

IEnumerable<int> intList = Enumerable.Range(1, 10);
int intSum = intList.Sum();
int intSumOdds = intList.Where(x => x % 2 == 1).Sum();
double intAverage = intList.Average();

This is more efficient since the sequence returned by Enumerable.Range is generated "lazily" as it is enumerated. On the other hand, when the sequence is converted to a List<int> then all of the values must be held in memory at once.



回答2:

You wouldn't fill an existing list with LINQ; you'd create an Enumerable and then convert it to a list. In this case, it's as simple as

IList<int> intList = Enumerable.Range(1, 10).ToList();


回答3:

I think what you're looking for in the specific case is Enumerable.Range(). From there, if you want to you can filter the list by using Wheres and such. For instance, if i wanted all the numbers from whose power of two is below 100 i'd do something like Enumerable.Range(1,100).Where(i => i * i < 100). This is very common in functional languages like Haskell where something similar is this: filter (\i -> i * i < 100) [1..100]

A specific example to replace your function:

Enumerable.Range(1,10).Where(x => x%2 == 1).Sum();
//add separate sum and averages here


回答4:

List<T> has a constructor that takes an IEnumerable<T> as a parameter. You can use Enumerable.Range to generate the numbers.

List<int> values = new List<int>(Enumerable.Range(1, 10));

If you want to add the values to a previously constructed List<T>, you can use List<T>.AddRange in the same way:

values.AddRange(Enumerable.Range(1, 10));