Linq and conditional sum - linq

I have a class and a list as below:
class C1
{
int RecType ...;
decimal Income ...;
decimal Outcome ...;
}
List<C1> myList ...;
The list is loaded with several records, and they have various values in RecType
What I want is to calculate total on Income and Outcome but only for a certain value of RecType
Here's a pseudo code of what I need to get
totalIncome = myList.Sum(Income).Where(RecType==1);
How can I accomplish this with linq?
Thank you

totalIncome = myList.Where(x => x.RecType == 1).Select(x => x.Income).Sum();
First you filter on the record type (Where); then you transform by Selecting the Income of each object; and finally you Sum it all up.
Or for a slightly more terse version:
totalIncome = myList.Where(x => x.RecType == 1).Sum(x => x.Income);

totalIncome = myList.Sum(c=>
(c.RecType==1 ? c.Income : 0));

Related

LINQ: how to do "flat" collection instead of "nested" [duplicate]

I have a LINQ query which returns IEnumerable<List<int>> but i want to return only List<int> so i want to merge all my record in my IEnumerable<List<int>> to only one array.
Example :
IEnumerable<List<int>> iList = from number in
(from no in Method() select no) select number;
I want to take all my result IEnumerable<List<int>> to only one List<int>
Hence, from source arrays:
[1,2,3,4] and [5,6,7]
I want only one array
[1,2,3,4,5,6,7]
Thanks
Try SelectMany()
var result = iList.SelectMany( i => i );
With query syntax:
var values =
from inner in outer
from value in inner
select value;
iList.SelectMany(x => x).ToArray()
If you have a List<List<int>> k you can do
List<int> flatList= k.SelectMany( v => v).ToList();
Like this?
var iList = Method().SelectMany(n => n);

Linq : How do I test a List<bool> for condition where any one of its values == true?

I have a list,
List<bool> MyList;
MyList.Add(true);
MyList.Add(false);
MyList.Add(false);
What is a clean way to use linq to test if any value is true? I tried
MyList.Find(SomeBoolean=>SomeBoolean)
but the result is weird.
Try :
bool test = MyList.Any(x => x);
But you have to initialize your list before inserting anything.
Use Any
var anyTrue = MyList.Any(i => i);
If you want to List all the true value
List<bool> MyList = new List<bool>();
MyList.Add(true);
MyList.Add(false);
MyList.Add(false);
var listTrue = MyList.Where(c => c);
I wonder, what is your actual Class because if you want to .Find is the same result.
var b = MyList.Find(c => c)
maybe you forgot to declare the var or DataType?
myList is a list of bool
myList= getSelectedChannels();
List allTrue= myList.FindAll(a => a == true);
allTrue will be a list of bool that match the criteria (bool is true). Now just say allTrue.Count to get the number of items in that list.

Better way to check resultset from LINQ projection than List.Count?

Is there a better way to check if a LINQ projection query returns results:
IList<T> TList = db.Ts.Where(x => x.TId == 1).ToList(); // More canonical way for this?
if (TitleList.Count > 0)
{
// Result returned non-zero list!
string s = TList.Name;
}
You can use Any(), or perhaps more appropriately to your example, SingleOrDefault(). Note that if you are expecting more than one result and plan to use all of them, then it doesn't really save anything to use Any() instead of converting to a List and checking the length. If you don't plan to use all the results or you're building a larger query that might change how the query is performed then it can be a reasonable alternative.
var item = db.Ts.SingleOrDefault( x => x.TId == 1 );
if (item != null)
{
string s = item.Name;
...
}
or
var query = db.Ts.Where( x => x.Prop == "foo" );
if (query.Any())
{
var moreComplexQuery = query.Join( db.Xs, t => t.TId, x => x.TId );
...
}

How can I Make a LINQ query expression dynamic

I'm trying to implement cascading controls using the following LINQ query expression.
The idea is that I have three option lists represented by the tables OptionA, OptionB and OptionC and a view called OptionIndex with one column each for OptionA_ID, OptionB_ID, OptionC_ID and that table has of all the combinations of tags from the option lists that are in use. Left outer joining the OptionIndex on the option list produces a boolean for the Disabled attributed in the option tag.
How do I make the on clause, which is .Where(...) in the following sample code, allow for any combination of the controls being used?
For example, lets say the user initially selects option value 123 in OptionA. The code to return the Values, Labels and Disabled booleans for OptionC would look like the following:
from t1 in OptionCs
from t2 in OptionIndexes.Where(x => t1.OptionC_ID == x.OptionC_ID && new List<int> { 123 }.Contains(x.OptionA_ID)).DefaultIfEmpty()
group new {t1, t2} by new { t1.OptionC_ID, t1.Label } into g
select new { g.Key.OptionC_ID, g.Key.Label, Disabled = g.Count(t => t.t2.OptionC_ID == null) > 0 }
Then lets say the user selects option values 456 and 789 in OptionB. The code to return the Values, Labels and Disabled booleans for OptionC change to:
from t1 in OptionCs
from t2 in OptionIndexes.Where(x => t1.OptionC_ID == x.OptionC_ID && new List<int> { 123 }.Contains(x.OptionA_ID) && new List<int> { 456, 789 }.Contains(x.OptionB_ID)).DefaultIfEmpty()
group new {t1, t2} by new { t1.OptionC_ID, t1.Label } into g
select new { g.Key.OptionC_ID, g.Key.Label, Disabled = g.Count(t => t.t2.OptionC_ID == null) > 0 }
To make the example code easier to understand I used new List<int>. In the actual project, however I would be passing the integers from the option list in as integer arrays from the controls themselves.
The trick is somehow making the query expression dynamic so that it can represent any combination of 0 to N multi-select controls being used or passing something that tells the join to accept any value for any given control such as
{x.OptionB_ID.Any}.Contains(x.OptionB_ID)
What is the best way to handle this?
Thanks!
Distilling your issue down to a simple example, consider this list of integers:
List<int> l = new List<int> { 1, 25, 3, 99, -23, 0, 15, 75 };
Say that you want to conditionally filter this list based on external criteria. Sometimes you want positive numbers, sometimes you want numbers smaller than 50, sometimes you want numbers divisible by 5, or any combination of these. Applying all filters with a static expression would look like this:
l.Where(n => n > 0).Where(n => n < 50).Where(n => n % 5 == 0);
To apply any or all of these dynamically, just build the LINQ query in pieces:
// These switches simulate your external conditions.
bool conditionA = true;
bool conditionB = false;
bool conditionC = true;
IEnumerable<int> myList = l;
if (conditionA) { myList = myList.Where(n => n > 0 ); }
if (conditionB) { myList = myList.Where(n => n < 50 ); }
if (conditionC) { myList = myList.Where(n => n % 5 == 0); }
With the switches set as in my example, the output is 25, 15, 75.
Side note: if you are not aware of it, use LINQPad to experiment with things like this. It is a fantastic tool for essentially executing code interactively, be it LINQ code or not. When I built the above sample, I inserted myList.Dump(); calls after each of the last 4 lines so I could see how each filter was applied. Here is the output:

Linq query: MAX in WHERE

I have a long query that returns
Item {
DateTime entryDate
.....
}
I like to combine the result of this query with another table
Value {
DateTime date,
double value
}
such that if entryDate >= CUTOFF, then take the value on CUTOFF, else take the value on entryDate. In other words, I'd want to achieve:
SELECT Item.*, Value.value WHERE
MIN( Item.entryDate, CUTOFF ) == Value.date
Excuse my syntax, but that's the idea.
EDIT: After some trial and error, I came up with this linq-to-sql query:
from iValue in Values
join iItem in ... (long query)
let targetDate = iItem.EntryDate > CUTOFF ? iItem.EntryDate : CUTOFF
where iValue.Date == targetDate
select new
{
iItem,
targetDate,
iValue
}
Thanks for your help.
yourLongQuery.Where(y => y.Item.entryDate == Value.date || CUTOFF == Value.date)
.Select(x => new {
entrydate = (x.Item.entryDate < CUTOFF ? x.Item.entryDate : CUTOFF),
/*rest of x.Item properties here */ ,
x.Value.date,
x.Value.value
});
Filter the query, Combine the two items into one item and modify the first item
Given that you've returned your data from your Item query and that the Value table is relatively small then this is a nice way to go:
var lookup = values.ToLookup(v => v.date, v => v.value);
var query =
from i in items
let c = i.entryDate < CUTOFF ? i.entryDate : CUTOFF
let v = lookup[c].FirstOrDefault()
select new
{
Item = i,
Value = v,
};
The ToLookup extension is very useful and often overlooked.
such that if entryDate >= CUTOFF, then take the value on CUTOFF, else
take the value on entryDate. In other words, I'd want to achieve:
SELECT Item.*, Value.value WHERE MAX( Item.entryDate, CUTOFF ) ==
Value.date
This is contradictory - if entryDate >= CUTOFF then take the value on CUTOFF imples that you want MIN(Item.entryDate, CUTOFF), not MAX.
Having said that, you just want to select the value.Value that matches each item of your query. Each item should look up the relevant value which matches your MAX (or, I believe, MIN) statement.
query.Select(item =>
{
var matchingValue = Values.Single(v =>
v.date == Min(item.entryDate, CUTOFF));
return new { item, matchingValue.value };
});
This will return an IQueryable of anonymous { Item, double } objects.
If you require this to be a executed as a single SQL statement you'll need to do some refactoring. A good start is to swap matchingValue into a single statement.
query.Select(item => new { item, context.Values.Single(v =>
v.date == Min(item.entryDate, CUTOFF)).value });
I don't have a Visual Studio in front of me to confirm, but I am not sure that the Math.Min function is mapped in LINQ-to-SQL. Let's assume it's not.
query.Select(item => new { item, context.Values.Single(v =>
v.date == (item.entryDate < CUTOFF ? item.entryDate : CUTOFF)).value });
I believe that will resolve to a single query if you execute it with a .ToList() but can't confirm until I have some tools in front of me. Test it with SQL profiler to be sure.

Resources