Home > Mobile >  How to select multiple elements into array in Linq query?
How to select multiple elements into array in Linq query?

Time:05-06

Net core application. I have below query in my application

 var result  = sourceProposal.Quotes
      .Where(x=>x.QuotationId == sourceQuoteId)
      .FirstOrDefault()
      .QuoteLines.Select(x=>(x.Quantity,x.WtgType)).ToArray();

This yields in two array elements such as

0 element   1, "string1"
1 element   2, "string2"

What I am expecting is

(int[] sourceQuantity, string[] destinationTurbineType) = sourceProposal.Quotes
           .Where(x=>x.QuotationId == sourceQuoteId)
           .FirstOrDefault()
           .QuoteLines.Select(x=>(x.Quantity,x.WtgType)).ToArray();

I want to copy to tuple which has int[] sourceQuantity, string[] destinationTurbineType this piece of code is not working and throwing error does not contain definition for destructor and no accessible extension method Descontruct accepting first argument of type int(sourceQuantity, string destinationTurbineType)[].

Can someone help me to copy values to sourceQuantity and destinationTurbineType. Any help would be appreciated. Thanks

CodePudding user response:

Select<TSource,TResult> returns enumerable/queryable of the type returned by selector (IEnumerabe<TResult>/IQueryable <TResult>).

If you want to achieve this with LINQ you can use Aggregate:

// note that sourceQuantity and destinationTurbineType would be lists, not arrays
var (sourceQuantity, destinationTurbineType) = sourceProposal.Quotes
    .Where(x=>x.QuotationId == sourceQuoteId)
    .FirstOrDefault()
    .QuoteLines
    .Aggregate((ints: new List<int>(), strs: new List<string>()), (aggr, curr) =>
    {
        aggr.ints.Add(curr.Quantity);
        aggr.strs.Add(curr.WtgType);
        return aggr;
    });

Or just use simple for loop and copy data to destination arrays (possibly move to some extension method). Something along this lines:

var quoteLines = sourceProposal.Quotes
    .Where(x=>x.QuotationId == sourceQuoteId)
    .FirstOrDefault()
    .QuoteLines; // assuming it is materialized collection with indexer like an array or list
int[] sourceQuantity = new int[quoteLines.Length]; // or Count
string[] destinationTurbineType = new string[quoteLines.Count()];
for(int i = 0; i < quoteLines.Length; i  )
{
   var curr = quoteLines[i];
   sourceQuantity[i] = curr.Quantity;
   destinationTurbineType[i] = curr.WtgType;
}

CodePudding user response:

Currently there is no built-in LINQ method to do this. But you could write your own extension method. Something like the following:

public static class EnumerableExtensions
{
    public static (TFirst[] xs, TSecond[] ys) Unzip<TFirst, TSecond>(this IEnumerable<(TFirst, TSecond)> zipped)
    {
        var xs = new List<TFirst>();
        var ys = new List<TSecond>();
        foreach (var (x, y) in zipped)
        {
            xs.Add(x);
            ys.Add(y);
        }
        return (xs.ToArray(), ys.ToArray());
    }
}

var (xs, ys) =
    new[] { 1, 2, 3 }
    .Zip(new[] { "a", "b", "c" })
    .Unzip();

Console.WriteLine(string.Join(", ", xs)); // 1, 2, 3
Console.WriteLine(string.Join(", ", ys)); // a, b, c

Or in the case of your example, you could then use:

(int[] sourceQuantity, string[] destinationTurbineType) = sourceProposal.Quotes
           .Where(x=>x.QuotationId == sourceQuoteId)
           .FirstOrDefault()
           .QuoteLines.Select(x=>(x.Quantity,x.WtgType)).Unzip();
  • Related