Filtering Null values in Select - linq

I have IQueryable list of objects of type T which I want to transform into objects of type K
List<K> tranformedList = originalList.Select(x => transform(x)).ToList();
the transform function returns null if it cannot tranform the objects.If I want to filter out null elements can I call
List<K> tranformedList = originalList.Select(x => transform(x))
.Where(y => y != default(K))
.ToList();
or is there any other way of filtering out null elements when calling Select in LINQ ?

Can't you just do something like this:
List<K> tranformedList = originalList.Select(x => tranform(x))
.Where(y => y != null) //Check for nulls
.ToList();

What about
List<K> tranformedList = originalList
.Select(transform)
.OfType<K>()
.ToList()
Takes care of unboxing an getting rid of nulls at the same time (especially when K is a struct)
David B I dont believe you that your code .Where(y => y != null) works when K is an int! There is NO WAY you will get that code to compile if K is an int!

List<K> tranformedList = originalList.Select(x => transform(x))
.Where(y => !string.IsNullOrEmpty(y))
.ToList();
After your Select linq query, filter null values with !string.IsNullOrEmpty("string") or string.IsNullOrWhiteSpace("string") in your Where query.

Use Where Instead of Select (Linq).
Where returns the list without null values directly
List tranformedList = originalList.Where(x => x != null).ToList();

You could try a for loop and add the non nulls to the new transformed list.
foreach (var original in originalList)
{
K transformed = tranform(orignal);
if (transformed != null)
{
tranformedList.Add(transformed);
}
}
or you could try
List<K> tranformedList = (from t in
(from o in originalList
select tranform(o))
where t != null
select t).ToList();
I think Nathan's works as well but is less verbose

Related

How to compare IEnumerable<string> for null in Linq query

For the following query:
var result = from sch in schemeDashboard
join exp in Expenditure on sch.schemeId equals exp.SchemeCode
into SchExpGroup
where sch.SectorDepartmentId == selectedDepartmentId &&
sch.YearCode == StateManager.CurrentYear
orderby sch.ADPId
select new
{
ModifiedAmounts = SchExpGroup.Select(a => a.ModifiedAmounts),
ProjectName = sch.schemeName,
ADPNo = sch.ADPId,
Allocation = sch.CurrentAllocation,
Expenditures = from expend in SchExpGroup
where expend.YearCode == StateManager.CurrentYear &&
expend.DepartmentId == selectedDepartmentId &&
InvStatus.Contains(expend.Status)
orderby expend.ADPId
group expend by expend.InvoiceId
};
I want to filter the above query on a condition so that result gives only those records where "ModifiedAmounts" are not null. I have tried as follow:
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.ModifiedAmounts != null));
}
but this gives error as:
Cannot compare elements of type
'System.Collections.Generic.IEnumerable`1'. Only primitive types,
enumeration types and entity types are supported.
Any suggestions as I am lost as how to rephrase the filtered query.
I think the problem is that ModifiedAmounts will never be null. Select will return an empty list. Unless SchExpGroup is null in which case you will get a null reference exception.
Try changing your code to
result = result.Where(a => a.ModifiedAmounts.Any());
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.!ModifiedAmounts.Any());
}

Getting the Error in my code when framing LINQ

My Code:
var lastName = employees
.Where(a => a.Number ==
(dm.MTM.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault()))
.Select(z => z.LastName)
.FirstOrDefault();
Error Message:
Unable to create a constant value of type 'XXX.Models.Mt.MTM'. Only primitive types or enumeration types are supported in this context.
Try:
int? num = dm.MTM.Where(b => b.MTT.IsManager).Select(c => c.Number).FirstOrDefault();
var lastName = employees.Where(a => a.Number == num).Select(z => z.LastName).FirstOrDefault();
But you should add a check
if (num == null)
{
// bad things, don't execute second query
}
between the two instructions.
The error is because in an Entity Framework query you can't do "things" too much fancy, like the things necessary to calculate num.
Try:
// Calculate the number outside of the main query
// because the result is fixed
var nb = dm.MTM
.Where(b => b.MTT.IsManager)
.Select(c => c.Number)
.FirstOrDefault();
// Perform the main query with the number parameter already calculated before
string lastName = String.Empty;
if (nb != null) // if null no need to run the query
{
lastName = employees
.Where(a => a.Number == nb)
.Select(z => z.LastName)
.FirstOrDefault();
}
You don't need to get the number from the database for each employee, calculate the value before running your main query.
This will be faster, less error-prone and better for caching.

try parse in linq

Hi I have a linq query as below
var perChange = (from data in globalDS.Tables[0].AsEnumerable().AsParallel()
select data.Field<double>("PercentChange")).ToList();
Now the dataset globalDS contains null as well as varchar values in them. So there is an obvious type cast error that is generated. Is there a way to try.Parse the value in "Percentage Change" column and select only the valid fields.
DataRow.Field supports nullable types:
List<double> result = globalDS.Tables[0].AsEnumerable().AsParallel()
.Where(r => r.Field<double?>("PercentChange").HasValue)
.Select(r => r.Field<double?>("PercentChange").Value)
.ToList();
Edit: Since you have mentioned that the field contains strings instead of doubles:
List<double> result = globalDS.Tables[0].AsEnumerable().AsParallel()
.Select(r => r.Field<string>("PercentChange").TryGetDouble())
.Where(nullDouble => nullDouble.HasValue)
.Select(nullDouble => nullDouble.Value)
.ToList();
I've used this extension to try-parse a string to double? which is safer than parsing "on the fly" into the local variable, especially with AsParallel:
public static Double? TryGetDouble(this string item, IFormatProvider formatProvider = null)
{
if (formatProvider == null) formatProvider = NumberFormatInfo.CurrentInfo;
Double d = 0d;
bool success = Double.TryParse(item, NumberStyles.Any, formatProvider, out d);
if (success)
return d;
else
return null;
}
How about this:
double temp;
var perChange = (
from data in globalDS.Tables[0].AsEnumerable().AsParallel()
where !data.IsNull("PercentChange")
&& double.TryParse(data.Field<string>("PercentChange"), out temp)
select double.Parse(data.Field<string>("PercentChange"))
).ToList();
Try a select using a where clause in which you check the type. This would be something like: where x != null && TypeOf(x) == double

orderby in linq only when column is not null using lambda

Please let me know how can I can use orderby in linq only when a particular column is not null using lambda expression:
var list= // result returned from sql stored proc
list.orderby(s=>s.empid!=null).select(p=>p) //something like this
Is it possible to include a condition to perform orderby on the list?
var list = _context.Products
.Where(p => p.EmpId != null)
.OrderBy(p => p.EmpId)
.Select(p => p)

How to make a linq Sum return null if the summed values are all null

I have a LINQ query that looks like this...
var duration = Level3Data.AsQueryable().Sum(d => d.DurationMonths);
If all the d.DurationMonths values are null the Sum returns 0. How can I make the Sum return null if all the d.DurationMonths are null? Or do I need to run a separate query first to eliminate this situation before performing the sum?
Along with the previous suggestion for an extension method - you could use a ternary operator...
var duration = Level3Data.AsQueryable().Any(d => d.DurationMonths.HasValue)
? Level3Data.AsQueryable().Sum(d => d.DurationMonths)
: null;
You can use Aggregate to provide custom aggregation code :
var items = Level3Data.AsQueryable();
var duration = items.Aggregate<D,int?>(null, (s, d) => (s == null) ? d.DurationMonths : s + (d.DurationMonths ?? 0));
(assuming the items in Level3Data are of type D)
var outputIndicatorSum = (from OutputIndicatorTable in objDataBaseContext.Output_Indicators
where OutputIndicatorTable.Output_Id == outputId
select (int?)OutputIndicatorTable.Status).Sum();
int outputIndicatorSumReturn = Convert.ToInt32(outputIndicatorSum);
return outputIndicatorSumReturn;
You can explicitly type cast non-nullable varaible into nullable type.
i.e, select (int?)OutputIndicatorTable.Status).Sum();
Using Sum alone, this is impossible. As you indicated in your question, you will need to check for this situation before you call Sum:
var q = Level3Data.AsQueryable();
var duration = q.All(d => d.DurationMonths == null)
? null
: q.Sum(d => d.DurationMonths);
If you would like the result without two queries try:
var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths);
If you want zero instead of null as the result of this query use:
var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths) ?? 0;

Resources