using dt.AsEnumerable().Sum for columns having string/null value - c#

I an using following way to get total of a column from a datatable
string total = dt.AsEnumerable().Sum(x => x.Field<decimal>("col1")).ToString();
This works fine when all the values of col1 are number.
My question is- lets consider if any one value of col1 is string or null or anything else other than number, the above code will throw error obviously.
Is there any way to check whether the value is number and use '0' instead if value is not number.
I tried -
string total = dt.AsEnumerable().Sum(x => x.Field<decimal>("col1") is int ? x.Field<decimal>("col1") : 0).ToString();
but not sure if it the correct way.
Please help

If it's not a decimal but a string you would even get a InvalidCastException in the Field<T> method. So you have to know what type it is.
I assume that Col1 can be null, Field<T> supports nullable types:
decimal total = dt.AsEnumerable()
.Sum(r => r.Field<decimal?>("Col1") ?? 0);
or without replacing null with 0:
decimal? total = dt.AsEnumerable()
.Sum(r => r.Field<decimal?>("Col1")); // use total.HasValue and total.Value
Presuming string, you could use decimal.TryParse:
decimal d = 0;
decimal total = dt.AsEnumerable()
.Where(r => decimal.TryParse(r.Field<string>("Col1"), out d))
.Sum(r => d);
If you don't know what type it is you could use object.ToString:
decimal total = dt.AsEnumerable()
.Where(r => !r.IsNull("Col1") && decimal.TryParse(r["Col1"].ToString(), out d))
.Sum(r => d);
Apart from that, why do you store the converted number again in a string variable?

Related

unable to cast of type 'System.Data.EnumerableRowCollection`1[System.String]' to type 'System.IConvertible'

I need the column value(FundSpreadDurationContribution) of a data table(residing in dataset) through LINQ which fetches the above error (heading)
Elaborated: when a row cell has value Spread Duration--IR Swap, need the corresponding column cell FundSpreadDurationContribution value.
double testvalue = Convert.ToDouble(raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap").Select(s => s.Field<string>(RaptorColumns.FundSpreadDurationContribution)))
I am learner of LINQ.
// First check if this query will return any results
var records =
raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap");
// CHeck if any result
if (records.Any())
{
// We have results so let's go through each record and try to get that value
// converted to a double
List<double> values = new List<double>();
List<string> badValues = new List<string>();
foreach (var thisRecord in records)
{
var fsdc = thisRecord.Field<string>(RaptorColumns.FundSpreadDurationContribution);
if (!string.IsNullOrWhiteSpace(fsdc))
{
double val = 0;
if (double.TryParse(fsdc, val))
{
values.Add(val);
}
else
{
badValues.Add(fsdc);
}
}
}
// Do whatever you need to do with values here
// and bad values here
}
Where returns a collection, which cannot be converted to a double. Use one of these Linq methods to get one answer to convert:
Single
SingleOrDefault
First
FirstOrDefault
This is just playing around with Datatypes which fixed the type casting issue
var sumFundSpreadDuration = raptorDS.Tables[RaptorTable.DurationContribBySector].AsEnumerable().Where(r =>
r.Field<string>(RaptorColumns.FundCode) == fundDescriptionColumn &&
r.Field<string>(RaptorColumns.Component) == Component.B8_DURATION_CONTRIBUTION_BY_SECTOR &&
r.Field<string>(RaptorColumns.Sector) == "Spread Duration--IR Swap")
.Select(s => s.Field<double?>(RaptorColumns.FundSpreadDurationContribution)).FirstOrDefault();
If you see the datatype of variable is changed to Variant from double. Also, the datatype of column FundSpreadDurationContribution is changed to double. Thanks to CodingYoshi for providing insights of datatypes in linq

Query values from a C# Generic Dictionary using LINQ

Here's the code i have:
Dictionary<double, long> dictionary = new Dictionary<double, long>();
dictionary.Add(99, 500);
dictionary.Add(98, 500);
dictionary.Add(101, 8000);
dictionary.Add(103, 6000);
dictionary.Add(104, 5);
dictionary.Add(105, 2000);
double price = 100;
the query i want is:
the key that is nearest price AND with the lowest value.
so in the above example it should return 99.
how do i code this in LINQ ?
i have seen alot of linq examples but i cannt adapt any of them to my needs b/c my query has 2 conditions.
thanks for any help.
edit:
based on comments from #nintendojunkie and #DmitryMartovoi i have had to rethink my approach.
if i prioritize key closest to price then resulting value may not be the lowest and if i prioritize value first then the key may be too far from price so the query will have to prioritize BOTH the key and value the same and give me the lowest value with the closest key to price. both key and value are equally important.
can anyone help on this?
thanks
Don't forget - you use dictionary. Dictionary has only unique keys. I think you consider this structure as List<KeyValuePair<double, long>>. If so - please look to this example:
var minimumKeyDifference = dictionary.Min(y => Math.Abs(y.Key - price));
var minimumItems = dictionary.Where(x => Math.Abs(x.Key - price).Equals(minimumKeyDifference));
var desiredKey = dictionary.First(x => x.Value.Equals(minimumItems.Where(y => y.Key.Equals(x.Key)).Min(y => y.Value))).Key;
You say that you need to find the closest price and the lowest value, but you don't define the rules for attributing precedence between two. In the below, I'm attributing them equal precedence: a price distance of 1 is equivalent to a value of 1.
var closest =
dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price) + kvp.Value).First();
The OrderBy(…).First() should be replaced by a MinBy(…) operator, if available, for performance.
Edit: If the value is only meant to serve as a tiebreaker, then use this (also posted by Giorgi Nakeuri):
var closest =
dictionary.OrderBy(kvp => Math.Abs(kvp.Key - price))
.ThenBy(kvp => kvp.Value)
.First();
You can do it this way:
var result = dictionary.Select(c => new { c.Key, Diff = Math.Abs(price - c.Key) + Math.Abs(price - c.Value), c.Value }).OrderBy(c => c.Diff).FirstOrDefault();
The following works if you change your dictionary key's data type to decimal instead of double.
decimal price = 100;
decimal smallestDiff = dictionary.Keys.Min(n => Math.Abs(n - price));
var nearest = dictionary.Where(n => Math.Abs(n.Key - price) == smallestDiff)
.OrderBy(n => n.Value).First();
If you use double this may fail due to rounding issues, but decimal is preferred for anything having to do with money to avoid those issues.
var price = 100.0;
var nearestKey = (from pair in dictionary
let diff = Math.Abs(pair.Key - price)
select new {Key = pair.Key, Diff = diff}
order by diff desc).First().Key;
var minValue = dictionary[nearestKey];
Maybe you want a magic linq query but i suggest to try the in below.
public static class MyExtensions
{
public static double? GetNearestValue (this IDictionary<double, long> dictionary, double value)
{
if (dictionary == null || dictionary.Count == 0)
return null;
double? nearestDiffValue = null;
double? nearestValue = null;
foreach (var item in dictionary) {
double currentDiff = Math.Abs (item.Key - value);
if (nearestDiffValue == null || currentDiff < nearestDiffValue.Value) {
nearestDiffValue = currentDiff;
nearestValue = item.Value;
}
}
return nearestValue;
}
}
And call like this
Console.WriteLine (dictionary.GetNearestValue (100d));
var min = dictionary
.OrderBy(pair => pair.Value)
.Select(pair =>
new
{
k = pair.Key,
d = Math.Abs(pair.Key - price)
})
.OrderBy(t => t.d)
.Select(t => t.k)
.FirstOrDefault();

float to string with no decimal value in C#

This is how I get previous greatest ID from my datasource and plus one to this value .
string _fID = (float.Parse("." + DBContext.Employees.OrderByDescending(x =>
x.EmpID).FirstOrDefault().EmpID.ToString()) + .00001f).ToString("F5");
And I get _fID = 0.00002 .
But what I want is the string with no decimal value .
Eg. _fID = 00002 .
What I've done is replacing like _fID = _fID.Replace("0.",""); .
Is there any short way to make this stuff ? Thanks you all :)
PS
Data Type of EmpID is nvarchar(5) .
I would suggest you stop using floating point types at all. Just use integers, as that's basically what you've got. (It's a shame that your data type is textual when you're logically just using integers.)
string currentHighest = DBContext.Employees
.Select(x => x.EmpID)
.OrderByDescending(x => x)
.FirstOrDefault();
// TODO: Handle currentHighest being null (empty table)
int nextId = (int.Parse(currentHighest) + 1).ToString("00000");

Casting a value to Decimal

Here is my code:
var finiGames = myRepos.Games
.Where(x => x.StatusGameId == (int)StatusGameEnum.Finish
&& x.EndDateTime > DateTime.Today)
.DefaultIfEmpty();
//error line
decimal? sum = finiGames.Sum(x => x.WinCost);
The error I am getting:
Error converting cast a value type "Decimal", because materializuemoe
value is null. The overall result of the type parameter or a request
to use a type that allows the value null.
What is the proper way to get a decimal??
You need to cast the WinCost to a nullable decimal inside the Sum
decimal? sum = finiGames.Sum(x => (decimal?)x.WinCost);
Try adding a ToList() to finiGames. It might kill your performance, but EF probably can't handle the conversion in the data (SQL) layer.
decimal sum = ((decimal?)finiGames.Sum(x => x.WinCost)) ?? 0;

sum column with linq to sql

I have a DataView in which I would like to sum a column called "Amount"
Now I know I can iterate thru the columns and get the sum but I was wondering if is possible using Linq to Sql?
String sum = Linq to Sql stuff here (doesn't have to be a string, can be any type)
Thanks,
rodchar
Assuming the Amount column is a double (could be another type)
double sum = Table.Select(t => t.Amount ?? 0).Sum();
Or
double sum = Table.Sum(t => t.Amount ?? 0).Sum();
Using the null coelescing operator will give you a default of 0 if t.Amount is null.
we can do this using the entity framework var sum=dbcontext.table.select(a=>a.columnname).Sum();
Excuse me for dataContext call syntax...
var sum = dataContext.Sum(x => x.Amount);
If you want to sum strings, you may want to use
var sum = string.Join(", ", dataContext.Select(x => x.StringColumn).ToArray());
Hope this works.

Categories

Resources