C# code to convert string to Double - c#

I am trying to convert some particular types of strings into double in c#. Normally, Convert.ToDouble() works all great but this one does not always return healthy strings. Which means that input does not always come in format of "4.2". SOmetimes it also comes in form of 4.4.2. Now, i can also not rely on positioning and truncating since it can be 10.11.445 tomorrow?
Any easy and short string manipulation function that I can apply on this scenario?

struct CalifornicatedNumber
{
private string value;
public CalifornicatedNumber(string value)
{
this.value = value;
}
static public implicit operator CalifornicatedNumber(string value)
{
return new CalifornicatedNumber(value);
}
static public implicit operator CalifornicatedNumber(double value)
{
return new CalifornicatedNumber(value.ToString());
}
static public implicit operator double(CalifornicatedNumber calif)
{
return double.Parse(MakeItMakeSense(calif.value));
}
static private string MakeItMakeSense(string calif)
{
if (calif.Count(x => x == '.') > 1)
calif = calif.Substring(0, calif.IndexOf('.', calif.IndexOf('.') + 1));
return calif;
}
}
then...
CalifornicatedNumber califnum;
califnum = "10.11.145";
Console.WriteLine(califnum);
if (califnum > 10) { Console.WriteLine("huzzah");}
califnum = 13.42;
Console.WriteLine(califnum);
if (califnum > 10) { Console.WriteLine("huzzahZah"); }
...this is the most foolish piece of code I have ever written.

After the posted comments I am assuming you would like to take the string 4.4.2 and convert it to double dropping everything after the second . (if found).
A method such as.
public static double ConvertStringToDouble(string inputString)
{
if (inputString.Count(x => x == '.') > 1)
inputString = inputString.Substring(0, inputString.IndexOf('.', inputString.IndexOf('.') + 1));
return double.Parse(inputString);
}

I would do an approach of creating a bunch of strategies for parsing the input text and then iterating through the strategies until a result is found.
First I'd define a tryParseDouble function:
Func<string, double?> tryParseDouble = t =>
{
double value;
if (double.TryParse(t, out value))
{
return value;
}
return null;
};
Then I'd create my list of strategies:
var strategies = new Func<string, double?>[]
{
t =>
{
var parts = t.Split('.');
return parts.Length > 1
? tryParseDouble(String.Join(".", parts.Take(2)))
: null;
},
tryParseDouble,
t => null,
};
And finally I'd get the result:
var text = "4.4.2";
var result =
strategies
.Select(p => p(text))
.Where(v => v != null)
.FirstOrDefault();
The result variable is a double? with the value parsed or a null if none of the strategies work. The final strategy, t => null, is there to be explicit but is not necessary in getting the final null result.
As new strategies are needed to parse different types of input text they can just be added to the list as needed.

I think this will do what you want according to your comments by parsing either the whole string (if no decimal points) or just the first two parts of the sting if there are multiple decimals.
String[] parts = stringVal.Split('.');
double doubleVal;
if (parts.length > 1)
{
doubleVal = Convert.ToDouble(parts[0] + "." + parts[1]);
}
else
{
doubleVale = Convert.ToDouble(stingVal);
}

Related

How to validate or compare string by omitting certain part of it

I have a string as below
"a1/type/xyz/parts"
The part where 'xyz' exists is dynamic and varies accordingly at any size. I want to compare just the two strings are equal discarding the 'xyz' portion exactly.
For example I have string as below
"a1/type/abcd/parts"
Then my comparison has to be successful
I tried with regular expression as below. Though my knowledge on regular expressions is limited and it did not work. Probably something wrong in the way I used.
var regex = #"^[a-zA-Z]{2}/\[a-zA-Z]{16}/\[0-9a-zA-Z]/\[a-z]{5}/$";
var result = Regex.Match("mystring", regex).Success;
Another idea is to get substring of first and last part omitting the unwanted portion and comparing it.
The comparison should be successful by discarding certain portion of the string with effective code.
Comparison successful cases
string1: "a1/type/21412ghh/parts"
string2: "a1/type/eeeee122ghh/parts"
Comparison failure cases:
string1: "a1/type/21412ghh/parts"
string2: "a2/type/eeeee122ghh/parts/mm"
In short "a1/type/abcd/parts" in this part of string the non-bold part is static always.
Honestly, you could do this using regex, and pull apart the string. But you have a specified delimiter, just use String.Split:
bool AreEqualAccordingToMyRules(string input1, string input2)
{
var split1 = input1.Split('/');
var split2 = input2.Split('/');
return split1.Length == split2.Length // strings must have equal number of sections
&& split1[0] == split2[0] // section 1 must match
&& split1[1] == split2[1] // section 2 must match
&& split1[3] == split2[3] // section 4 must match
}
You can try Split (to get parts) and Linq (to exclude 3d one)
using System.Linq;
...
string string1 = "a1/type/xyz/parts";
string string2 = "a1/type/abcd/parts";
bool result = string1
.Split('/') // string1 parts
.Where((v, i) => i != 2) // all except 3d one
.SequenceEqual(string2 // must be equal to
.Split('/') // string2 parts
.Where((v, i) => i != 2)); // except 3d one
Here's a small programm using string functions to compare the parts before and after the middle part:
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine(CutOutMiddle("a1/type/21412ghh/parts"));
Console.WriteLine("True: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a2/type/21412ghh/parts/someval"));
Console.WriteLine("False: " + CompareNoMiddle("a1/type/21412ghh/parts", "a1/type/21412ghasdasdh/parts/someappendix"));
}
private static bool CompareNoMiddle(string s1, string s2)
{
var s1CutOut = CutOutMiddle(s1);
var s2CutOut = CutOutMiddle(s2);
return s1CutOut == s2CutOut;
}
private static string CutOutMiddle(string val)
{
var fistSlash = val.IndexOf('/', 0);
var secondSlash = val.IndexOf('/', fistSlash+1);
var thirdSlash = val.IndexOf('/', secondSlash+1);
var firstPart = val.Substring(0, secondSlash);
var secondPart = val.Substring(thirdSlash, val.Length - thirdSlash);
return firstPart + secondPart;
}
}
returns
a1/type/parts
True: True
False: False
False: False
This solution should cover your case, as said by others, if you have a delimiter use it. In the function below you could change int skip for string ignore or something similar and within the comparison loop if(arrayStringOne[i] == ignore) continue;.
public bool Compare(string valueOne, string valueTwo, int skip) {
var delimiterOccuranceOne = valueOne.Count(f => f == '/');
var delimiterOccuranceTwo = valueTwo.Count(f => f == '/');
if(delimiterOccuranceOne == delimiterOccuranceTwo) {
var arrayStringOne = valueOne.Split('/');
var arrayStringTwo = valueTwo.Split('/');
for(int i=0; i < arrayStringOne.Length; ++i) {
if(i == skip) continue; // or instead of an index you could use a string
if(arrayStringOne[i] != arrayStringTwo[i]) {
return false;
}
}
return true;
}
return false;
}
Compare("a1/type/abcd/parts", "a1/type/xyz/parts", 2);

How can I use if condition to add values

I want to obtain a total of three values:
when none of the values is null, the total calculates successfully but when one or more of the values is null,
it returns an error:
"input string was not in correct format"
Below is the code:
double TotalVar = double.Parse(ExScore.Tables[0].Rows[i]["CAT1"].ToString()) +
double.Parse(ExScore.Tables[0].Rows[i]["CAT2"].ToString()) +
double.Parse(ExScore.Tables[0].Rows[i]["CAT3"].ToString()) +
double.Parse(ExScore.Tables[0].Rows[i]["EXAM"].ToString());
Use local function like this to safely parse data :
double Parse(string data)
{
return double.TryParse(data, NumberStyles.AllowDecimalPoint,
CultureInfo.InvariantCulture, out double val) ? val : 0;
}
if(ExScore == null || ExScore.Tables[0] == null ||
IsNullOrEmpty(ExScore.Tables[0].Rows[i]["CAT1"]) ||
IsNullOrEmpty(ExScore.Tables[0].Rows[i]["CAT2"]) ||
IsNullOrEmpty(ExScore.Tables[0].Rows[i]["CAT3"]) ||
IsNullOrEmpty(ExScore.Tables[0].Rows[i]["EXAM"])
)
{
//throw exception
//set value by default
}
//calcul normally
public bool IsNullOrEmpty(object value)
{
return value == null || string.IsNullOrEmpty(value.ToString());
}
Create a console app and test the app below. Everything you need is in the code below. Note: It is bad to direct cast strings without a minimal error handling, also you can/will have problems with "." or "," decimal separators in these casts. - Different regions use different decimal separators, and this can impact the quality of your results.
class Program
{
static void Main(string[] args)
{
//SumValues(
//ExScore.Tables[0].Rows[i]["CAT2"].ToString(),
//ExScore.Tables[0].Rows[i]["CAT3"].ToString(),
//ExScore.Tables[0].Rows[i]["EXAM"].ToString()
//);
Console.WriteLine(SumValues("100,32", "100,08", "100,10",null));
Console.WriteLine(SumValues("abcsdf", "ba123", "100,10", null));
Console.WriteLine(SumValues("100,32", "100,08", "100,10", null));
Console.ReadLine();
}
//simple function that will try to sum any number of strings you pass
public static double SumValues(params string[] values)
{
double sum=0;
foreach (var item in values)
{
//if the string is null, empty or white space, proceed to the next iteration in the loop
if (string.IsNullOrWhiteSpace(item))
continue;
if (IsNumeric(item))
sum += double.Parse(item);
}
return sum;
}
//Minimal 'error handling' function to avoid exceptions parsing strings
public static bool IsNumeric(string s)
{
double output;
return double.TryParse(s, out output);
}
}

Getting expression text

I want to pass the name of a property of a model to a method. Instead of using the name as string, I am using lambda expression as it is easy to make a typo, and also property names may be changed. Now if the property is a simple property (e.g: model.Name) I can get the name from the expression. But if it is a nested property (e.g: model.AnotherModel.Name) then how can I get full text ("AnotherModel.Name") from the expression. For example, I have the following classes:
public class BaseModel
{
public ChildModel Child { get; set; }
public List<ChildModel> ChildList { get; set; }
public BaseModel()
{
Child = new ChildModel();
ChildList = new List<ChildModel>();
}
}
public class ChildModel
{
public string Name { get;set; }
}
public void GetExpressionText<T>(Expression<Func<T, object>> expression)
{
string expText;
//what to do??
return expText;
}
GetExpressionText<BaseModel>(b => b.Child); //should return "Child"
GetExpressionText<BaseModel>(b => b.Child.Name); //should return "Child.Name"
GetExpressionText<BaseModel>(b => b.ChildList[0].Name); //should return "ChildList[0].Name"
My first thought was to use expression.Body.ToString() and tweak that a bit, but you would still need to deal with Unary (convert) etc. Assuming this is for logging and you want more control, the below can be used for formatting as wanted (e.g. if you want Child->Name for display purposes, string.Join("->",..) can be used). It may not be complete, but should you find any unsupported types, they should be easy to add.
PS: this post was generated before the question was closed. Just noticed it was reopend and submitting it now, but I haven't checked if particulars have been changed.
public string GetName(Expression e, out Expression parent)
{
if(e is MemberExpression m){ //property or field
parent = m.Expression;
return m.Member.Name;
}
else if(e is MethodCallExpression mc){
string args = string.Join(",", mc.Arguments.SelectMany(GetExpressionParts));
if(mc.Method.IsSpecialName){ //for indexers, not sure this is a safe check...
return $"{GetName(mc.Object, out parent)}[{args}]";
}
else{ //other method calls
parent = mc.Object;
return $"{mc.Method.Name}({args})";
}
}
else if(e is ConstantExpression c){ //constant value
parent = null;
return c.Value?.ToString() ?? "null";
}
else if(e is UnaryExpression u){ //convert
parent= u.Operand;
return null;
}
else{
parent =null;
return e.ToString();
}
}
public IEnumerable<string> GetExpressionParts(Expression e){
var list = new List<string>();
while(e!=null && !(e is ParameterExpression)){
var name = GetName(e,out e);
if(name!=null)list.Add(name);
}
list.Reverse();
return list;
}
public string GetExpressionText<T>(Expression<Func<T, object>> expression) => string.Join(".", GetExpressionParts(expression.Body));
You could use the C# 6.0 feature: nameof(b.Child) "Used to obtain the simple (unqualified) string name of a variable, type, or member."
which will also change on renaming. But this will only return the propertyname and not the complete path. Returning a complete path will be difficult, because only one instance is passed.
Closest i know right now is by simply using expression.Body.ToString() which would result in b.ChildList.get_Item(0).Name as a result.
You would still have to remove the first b. from the string if not wanted, and you could go even further to your intended output with Regex by replacing the get_Item(0) with the typical Index-Accessor.
(Also i had to make the ChildList and the Name-Property of ChildModel public to get it to work)
This Should get you most of the way there:
public static string GetFullPath<T>(Expression<Func<T>> action)
{
var removeBodyPath = new Regex(#"value\((.*)\).");
var result = action.Body.ToString();
var replaced = removeBodyPath.Replace(result, String.Empty);
var seperatedFiltered = replaced.Split('.').Skip(1).ToArray();
return string.Join(".", seperatedFiltered);
}
It gets ugly quite quickly...
public static string GetExpressionText<T>(Expression<Func<T, object>> expression)
{
bool needDot = false;
Expression exp = expression.Body;
string descr = string.Empty;
while (exp != null)
{
if (exp.NodeType == ExpressionType.MemberAccess)
{
// Property or field
var ma = (MemberExpression)exp;
descr = ma.Member.Name + (needDot ? "." : string.Empty) + descr;
exp = ma.Expression;
needDot = true;
}
else if (exp.NodeType == ExpressionType.ArrayIndex)
{
// Array indexer
var be = (BinaryExpression)exp;
descr = GetParameters(new ReadOnlyCollection<Expression>(new[] { be.Right })) + (needDot ? "." : string.Empty) + descr;
exp = be.Left;
needDot = false;
}
else if (exp.NodeType == ExpressionType.Index)
{
// Object indexer (not used by C#. See ExpressionType.Call)
var ie = (IndexExpression)exp;
descr = GetParameters(ie.Arguments) + (needDot ? "." : string.Empty) + descr;
exp = ie.Object;
needDot = false;
}
else if (exp.NodeType == ExpressionType.Parameter)
{
break;
}
else if (exp.NodeType == ExpressionType.Call)
{
var ca = (MethodCallExpression)exp;
if (ca.Method.IsSpecialName)
{
// Object indexer
bool isIndexer = ca.Method.DeclaringType.GetDefaultMembers().OfType<PropertyInfo>().Where(x => x.GetGetMethod() == ca.Method).Any();
if (!isIndexer)
{
throw new Exception();
}
}
else if (ca.Object.Type.IsArray && ca.Method.Name == "Get")
{
// Multidimensiona array indexer
}
else
{
throw new Exception();
}
descr = GetParameters(ca.Arguments) + (needDot ? "." : string.Empty) + descr;
exp = ca.Object;
needDot = false;
}
}
return descr;
}
private static string GetParameters(ReadOnlyCollection<Expression> exps)
{
var values = new string[exps.Count];
for (int i = 0; i < exps.Count; i++)
{
if (exps[i].NodeType != ExpressionType.Constant)
{
throw new Exception();
}
var ce = (ConstantExpression)exps[i];
// Quite wrong here... We should escape string values (\n written as \n and so on)
values[i] = ce.Value == null ? "null" :
ce.Type == typeof(string) ? "\"" + ce.Value + "\"" :
ce.Type == typeof(char) ? "'" + ce.Value + "\'" :
ce.Value.ToString();
}
return "[" + string.Join(", ", values) + "]";
}
The code is quite easy to read, but it is quite long... There are 4 main cases: MemberAccess, that is accessing a property/field, ArrayIndex that is using the indexer of a single-dimensional array, Index that is unused by the C# compiler, but that should be using the indexer of an object (like the [...] of the List<> you are using), and Call that is used by C# for using an indexer or for accessing multi-dimensional arrays (new int[5, 4]) (and for other method calls, but we disregard them).
I support multidimensional arrays, jagged array s(arrays of arrays, new int[5][]) or arrays of indexable objects (new List<int>[5]) or indexable objects of indexable objects (new List<List<int>>). There is even support for multi-property indexers (indexers that use more than one key value, like obj[1, 2]). Small problem: printing the "value" of the indexers: I support only null, integers of various types, chars and strings (but I don't escape them... ugly... if there is a \n then it won't be printed as \n). Other types are not really supported... They will print what they will print (see GetParameters() if you want)

How to validate decimal places

Please let me know good way to validate decimal value, if decimal(4,2) it should accept 2 numeric and 2 decimal places.
var value = "44.29";
var dec = value.Split('.');
Then finding the length will can be used, I need a better culture specific way. I need a generic solution which can be applied to all decimal field.
Like:
validate(int before,int afterdecimal);
var valid = validate(2,2);
Need a generic cleaner solution for this
private static bool IsDecimal(string value, int before, int after)
{
if (value.Contains("."))
{
var parts = value.Split('.');
if (parts[0].Length == before && parts[1].Length == after)
return true;
}
else if(value.Length == before)
return false;
return true;
}
You can try like this:
[RegularExpression(#"^\d{1,2}(\.\d{0,2})$",ErrorMessage = "Value contains more than 2 decimal places")]
public decimal Value { get; set; }
If you whant just validate, try to use the mod:
44.29 % 1 = 0.29
From the above answers I was able to do it like this
string value = "2009.99";
if (IsDecimal(value, 4, 4))
{
Console.WriteLine("Valid");
}
private static bool IsDecimal(string value, int before, int after)
{
var r = new Regex(#"^\d{1," + before + #"}(\.\d{0," + after + #"})$");
return r.IsMatch(value);
}

Get Max() of alphanumeric value

I have a dictionary containg ID which are alphanumeric (e.g. a10a10 & d10a9) from which I want the biggest ID, meaning 9 < 10 < a ...
When I use the following code, d10a9 is MAX since 9 is sorted before 10
var lsd = new Dictionary<string, string>();
lsd.Add("a", "d10a10");
lsd.Add("b", "d10a9");
string max = lsd.Max(kvp => kvp.Value);
How can I get the Max value of the IDs with the Longest string combined?
I think you may try to roll your own IComparer<string>
class HumanSortComparer : IComparer<string>
{
public int Compare(string x, string y)
{
// your human sorting logic here
}
}
Usage:
var last = collection.OrderBy(x => x.Value, new HumanSortComparer()).LastOrDefault();
if (last != null)
string max = last.Value;
this works like a charm assuming IDs always start with "d10a":
int max = lsd.Max(kvp => Convert.ToInt32(kvp.Value.Substring(4)));
Console.Write(string.Format("d10a{0}", max));
One way would be to do this
string max =lsd.Where(kvp=>kvp.Value.Length==lsd.Max(k=>k.Value.Length)).Max(kvp => kvp.Value);
however I think that this method would evalute the max length for each item so you may be better to extract it to a variable first
int maxLength=lsd.Max(kvp=>kvp.Value.Length);
string max = lsd.Where(kvp=>kvp.Value.Length == maxLength).Max(kvp => kvp.Value);
If you are going to have null strings in there you may need to perform null checks too
int maxLength=lsd.Max(kvp=>(kvp.Value??String.Empty).Length);
string max = lsd.Where(kvp=>(kvp.Value??String.Empty).Length == maxLength).Max(kvp => kvp.Value);
Alternatively treat your string as Base36 number and convert to long for the max function and then convert back again to get the max string.
string max =lsd.Max(tvp=>tvp.Value.FromBase36()).ToBase36();
public static class Base36 {
public static long FromBase36(this string src) {
return src.ToLower().Select(x=>(int)x<58 ? x-48 : x-87).Aggregate(0L,(s,x)=>s*36+x);
}
public static string ToBase36(this long src) {
StringBuilder result=new StringBuilder();
while(src>0) {
var digit=(int)(src % 36);
digit=(digit<10) ? digit+48 :digit+87;
result.Insert(0,(char)digit);
src=src / 36;
}
return result.ToString();
}
}
Finally just just the Agregate extension method instead of Max as this lets you do all the comparison logic....
lsd.Agregate(string.Empty,(a,b)=> a.Length == b.Length ? (a>b ? a:b) : (a.Length>b.Length ? a:b));
This could doesn't have null checks but you easily add them in.
I think if you did this:
var max = lsd.OrderByDescending(x => x.Value)
.GroupBy(x => x.Value.Length)
.OrderByDescending(x => x.Key)
.SelectMany(x => x)
.FirstOrDefault();
It may give you what you want.
You need StringComparer.OrdinalIgnoreCase.
Without the need to use linq, the function that do that is quite simple.
Complexity is, of course, O(n).
public static KeyValuePair<string, string> FindMax(IEnumerable<KeyValuePair<string, string>> lsd)
{
var comparer = StringComparer.OrdinalIgnoreCase;
var best = default(KeyValuePair<string, string>);
bool isFirst = true;
foreach (KeyValuePair<string, string> kvp in lsd)
{
if (isFirst || comparer.Compare(kvp.Value, best.Value) > 0)
{
isFirst = false;
best = kvp;
}
}
return best;
}
Okay - I think you need to first turn each key into a series of strings and numbers - since you need the whole number to be able to determine the comparison. Then you implement an IComparer - I've tested this with your two input strings as well as with a few others and it appears to do what you want. The performance could possibly be improved - but I was brainstorming it!
Create this class:
public class ValueChain
{
public readonly IEnumerable<object> Values;
public int ValueCount = 0;
private static readonly Regex _rx =
new Regex("((?<alpha>[a-z]+)|(?<numeric>([0-9]+)))",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
public ValueChain(string valueString)
{
Values = Parse(valueString);
}
private IEnumerable<object> Parse(string valueString)
{
var matches = _rx.Matches(valueString);
ValueCount = matches.Count;
foreach (var match in matches.Cast<Match>())
{
if (match.Groups["alpha"].Success)
yield return match.Groups["alpha"].Value;
else if (match.Groups["numeric"].Success)
yield return int.Parse(match.Groups["numeric"].Value);
}
}
}
Now this comparer:
public class ValueChainComparer : IComparer<ValueChain>
{
private IComparer<string> StringComparer;
public ValueChainComparer()
: this(global::System.StringComparer.OrdinalIgnoreCase)
{
}
public ValueChainComparer(IComparer<string> stringComparer)
{
StringComparer = stringComparer;
}
#region IComparer<ValueChain> Members
public int Compare(ValueChain x, ValueChain y)
{
//todo: null checks
int comparison = 0;
foreach (var pair in x.Values.Zip
(y.Values, (xVal, yVal) => new { XVal = xVal, YVal = yVal }))
{
//types match?
if (pair.XVal.GetType().Equals(pair.YVal.GetType()))
{
if (pair.XVal is string)
comparison = StringComparer.Compare(
(string)pair.XVal, (string)pair.YVal);
else if (pair.XVal is int) //unboxing here - could be changed
comparison = Comparer<int>.Default.Compare(
(int)pair.XVal, (int)pair.YVal);
if (comparison != 0)
return comparison;
}
else //according to your rules strings are always greater than numbers.
{
if (pair.XVal is string)
return 1;
else
return -1;
}
}
if (comparison == 0) //ah yes, but were they the same length?
{
//whichever one has the most values is greater
return x.ValueCount == y.ValueCount ?
0 : x.ValueCount < y.ValueCount ? -1 : 1;
}
return comparison;
}
#endregion
}
Now you can get the max using OrderByDescending on an IEnumerable<ValueChain> and FirstOrDefault:
[TestMethod]
public void TestMethod1()
{
List<ValueChain> values = new List<ValueChain>(new []
{
new ValueChain("d10a9"),
new ValueChain("d10a10")
});
ValueChain max =
values.OrderByDescending(v => v, new ValueChainComparer()).FirstOrDefault();
}
So you can use this to sort the string values in your dictionary:
var maxKvp = lsd.OrderByDescending(kvp => new ValueChain(kvp.Value),
new ValueChainComparer()).FirstOrDefault();

Categories