tags:

views:

78

answers:

3

I'm trying to use LINQ:

IEnumerable<String> debtors = (from expense in CurrentExpenses
                               where expense.WhoPaid == username
                               select expense.WhoOwes.AsEnumerable()).Distinct();

(username and WhoPaid are strings, WhoOwes is ICollection<String>)

What I want to do is get an IEnumerable of, for each expense where username paid, all the people who owe for it. I'm not really sure how to do it. Here is the compiler error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<string>>' to 'System.Collections.Generic.IEnumerable<string>'. An explicit conversion exists (are you missing a cast?)

What is the correct syntax for this?

+3  A: 

The code you've provided doesn't compile because you're trying to assign a sequence of a sequence of strings (each top-level sequence coming from a specific expense) to a reference that expects a sequence of strings.

Going by the return-type of your query, I assume you only need a sequence containing all the debtors for the user? If so, you need to flatten the result sequence.

// implicitly IEnumerable<string>
var debtors = CurrentExpenses.Where(expense => expense.WhoPaid == username)
                             .Select(expense => expense.WhoOwes)
                             .SelectMany(debtors => debtors) // flatten sequence
                             .Distinct();

(you can use a single SelectMany clause to do the projection and flattening together.)

or, in query syntax:

var debtors = (from expense in CurrentExpenses
               where expense.WhoPaid == username
               from debtor in expense.WhoOwes
               select debtor).Distinct();

If you need to find all expenses paid by the user and their associated debtors, you can stop at the first filter:

// implicitly IEnumerable<Expense>
var expensesPaidByUser = CurrentExpenses.Where(expense => expense.WhoPaid == username);

The debtors associated with each expense are already encapsulated in theExpense object, so you probably don't need a query more complicated than this; it's already effectively a sequence of a sequence of debtors grouped by expense.

If you do want a separate type to hold an expense and its associated debtors, you can do this with an anonymous type, although I don't see why its necessary in your case:

// implictly IEnumerable<anonymousType>
var debtorsByExpense = CurrentExpenses.Where(expense => expense.WhoPaid == username)
                                      .Select(expense => new { Expense = expense, Debtors = expense.WhoOwes });
Ani
+1 for really nice answer
K.Hoffmann
+2  A: 

Use:

var debtors = ...

instead of

IEnumerable<String> debtors = ...

The return type of LINQ expressions is often difficult to determine for the programmer. The var keyword tells the compiler to infer the type automatically, so you don't need to. Hover your mouse cursor over var in your IDE to see what the compiler has inferred.

CesarGon
Why is that preferred? (I'm new to LINQ, thanks.)
Rosarch
Editing my answer to show it...
CesarGon
+1. Compiler is using two features in this case for LINQ. They are named 'Implicit Variable Types' (http://msdn.microsoft.com/en-us/library/bb384061.aspx) and 'Anonymous Types' (http://msdn.microsoft.com/en-us/library/bb397696.aspx)
Kyle B.
A: 

use this:

IEnumerable<IEnumerable<String>> debtors = (from expense in CurrentExpenses
                                      where expense.WhoPaid == username
                                      select expense.WhoOwes.AsEnumerable()).Distinct();

also u can do this:

var debtors = (from expense in CurrentExpenses
                                          where expense.WhoPaid == username
                                          select expense.WhoOwes.AsEnumerable()).Distinct();
SaeedAlg