How to test if a string array is boolean - c#

I need to test for all values being only "0" or "1" in a string array and tried the following code without success:
bool isBool = Array.TrueForAll(str, val => val.Trim() == "0" || val.Trim() == "1");
and
bool isBool = str.All(val => val.Trim() == "0" || val.Trim() == "1");
Is there a different way I have to do this because I'm using a || condition?

I'm assuming that you mean the values have to be exclusively all 1's or 0's? In that case you need to test each case separately. Your existing code is true when the array contains only 0's or 1's. It would be false if any of the values were 2 though. One solution:
var allAreZero = new string[] { " 0 ", " 0", " 0" };
var allAreOne = new string[] { " 1 ", "1", " 1" };
var mixedOnesAndZeros = new string[] { " 1 ", "0", " 1" };
private bool ArrayIsExclusivelyTrueOrFalse(string[] data)
{
return data.All(i => int.TryParse(i, out int value) && value == 0) ||
data.All(i => int.TryParse(i, out int value) && value == 1);
}
ArrayIsExclusivelyTrueOrFalse(allAreZero); // true
ArrayIsExclusivelyTrueOrFalse(allAreOne); // true
ArrayIsExclusivelyTrueOrFalse(mixedOnesAndZeros); // false

Try this
var isBool = !str.Select(s => s.Trim()).Distinct().Any(s => s != "0" && s != "1");

you can try Any() and return in the first failing condition !str.Any(x => x.Trim() != "0" && x.Trim() != "1")

If you want to ensure that all the values in your array are either ALL "0" or ALL "1" (but not a mix of "0" and "1", as I originally read it), then one way would be to ensure that the number of Distinct items (after trimming) has a Count of 1 (meaning they're all the same), and that the item is a member of the set of valid values (in the code below we just check the first item, since we already know they're all the same at that point).
For example:
var validValues = new[] {"0", "1"};
var isBool = str.Select(i => i.Trim()).Distinct().Count() == 1 &&
validValues.Contains(str[0].Trim());

Related

How to avoid using IF-Else and use inline if condition inside the .where() function?

q = q.Where(s =>
!matchingRecords.Contains(s.Id)
|| (s.SecId != null)
);
but the matchingrecords could be null or having 0 items in it since it's a list. So, in that case it would fail in the above code. I want to check this contains only if
the matching records is not null and have some elements else not.
One way is to put IF-Else block and repeat the code but I want to do it inline, how ?
So, if input conditions are:
matchingRecords is not null;
matchingRecords not empty (contains elements, .Count > 0);
no if-else usage allowed;
could it be done through ternary?
var list = matchingRecords?.Count > 0 ?
q.Where(s => !matchingRecords.Contains(s.Id) && s.SecId != null).ToList()
: new List<Record>();
matchingRecords? checks for null and .Count after checks for "not empty". If-else replaced with ternary, which would filter collection using Where or return new List<Record> on else case.
Sample:
class Program
{
private static List<int> matchingRecords; // It is null, we "forget" to initialize it
static void Main(string[] args)
{
var list = new List<Record>()
{
new Record { Id = 0, SecId ="Some SeqId" },
new Record { Id = 1, SecId = null },
new Record { Id = 2, SecId = "Another SeqId" },
};
var filteredRecords = FilterRecords(list);
}
static IEnumerable<Record> FilterRecords(IEnumerable<Record> q)
{
return matchingRecords?.Count > 0 ? // Checking for not null and not empty (if case)
q.Where(s => !matchingRecords.Contains(s.Id) && s.SecId != null)
: q; // else case
}
}
public class Record
{
public int Id { get; set; }
public string SecId { get; set; }
}
Not sure that properly reproduced your situation, so correct me if something is wrong.
q = q.Where(s => (matchingRecords != null && matchingRecords.Count > 0 &&
!matchingRecords.Contains(s.Id))
|| (s.SecId != null)
);
The condition matchingRecords != null && matchingRecords.Count > 0 will ensure !matchingRecords.Contains(s.Id) is executed only if matchingRecords has at least 1 record

Turn boolean-expression string into the .NET code

I have logic where customer specifies a string and my app tells to the customer if this string presents in the text, something like this:
internal const string GlobalText = "blablabla";
bool PresentInTheText(string searchString)
{
return GlobalText.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0;
}
Basically if text contains passed string return true otherwise false.
Now I want to make it more complex. Lets say if customer passes a string "foo && bar", and I need to return true if this text contains both "foo" and "bar" substrings, straightforward approach:
bool result;
if (!string.IsNullOrEmpty(passedExpression) &&
passedExpression.Contains(" && "))
{
var tokens = passedExpression.Split(new[] { " && " }, StringSplitOptions.RemoveEmptyEntries);
result = true;
foreach (var token in tokens)
{
if (GlobalText.IndexOf(token, StringComparison.OrdinalIgnoreCase) < 0)
{
result = false;
}
}
}
return result;
It works for expressions like A && B && C. But I want generalize the solution to support all boolean operators.
Let's say: ("foo" && "bar") || "baz". What would be the solution?
I would say take passed string, using regex add to all strings .IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 code, it would be like this:
("foo".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0 &&
"bar".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0)) ||
"baz".IndexOf(token, StringComparison.OrdinalIgnoreCase) < >= 0
and then turn this string into a function and execute using Reflections. What would be the best solution?
ETA:
Test cases:
bool Contains(string text, string expressionString);
string text = "Customers: David, Danny, Mike, Luke. Car: BMW"
string str0 = "Luke"
string str1 = "(Danny || Jennifer) && (BMW)"
string str2 = "(Mike && BMW) || Volvo"
string str3 = "(Mike || David) && Ford"
string str4 = "David && !BMW"
bool Contains(string text, string str0); //True - This text contains "Luke"
bool Contains(string text, string str1); //True - David and BMW in the text
bool Contains(string text, string str2); //True - Mike and BMW in the text
bool Contains(string text, string str3); //False - no Ford in the list
bool Contains(string text, string str4); //False - BMW in the list
You can solve this universally in the same way that a calculator, or a compiler, evaluates an expression:
Tokenize the string and identify each token as an operator (OP) or an operand (A, B, C, etc).
Convert the token sequence from infix (A OP B) to postfix (A B OP).
Evaluate the postfix token sequence.
Each of these steps can be done with a well known stack based algorithm, in linear time and space. Plus, if you use this method, it automatically extends to any binary operators you'd like to add later (addition, subtraction, fuzzy string match, etc etc).
To convert from infix to postfix: http://scriptasylum.com/tutorials/infix_postfix/algorithms/infix-postfix/
To evaluate the postfix:
http://scriptasylum.com/tutorials/infix_postfix/algorithms/postfix-evaluation/
The easiest way to do this would be to parse the input text and build an array of boolean "true" values, so you end up with something like this:
//Dictionary<string,List<string>> members;
members["Car"].Contains("BMW") // evals to True;
Alternatively, if there's no functional difference between any of the input entries (i.e. the variable evaluates to true as long as the word shows up in the input text), you can probably just build a list of strings rather than having to worry about using their classification as the dictionary key.
Then, you parse the equation strings and see if the values are present in the boolean list, if they are, you replace them in the original equation string with a 1. If they are not present, you replace them with a 0.
You end up with something that looks like this:
string str0 = "Luke" // "1"
string str1 = "(Danny || Jennifer) && (BMW)" // "(1 || 0) && (1)"
string str2 = "(Mike && BMW) || Volvo" // "(1 && 1) || 0"
string str3 = "(Mike || David) && Ford" // "(1 || 1) && 0"
string str4 = "David && !BMW" // "1 && !0"
Now, it's just a simple iterative string replace. You loop on the string until the only thing remaining is a 1 or a 0.
while (str.Length > 1)
{
if (str.Contains("(1 || 1)"))
str.Replace("(1 || 1)", "1");
if (str.Contains("(1 || 0)"))
str.Replace("(1 || 0)", "1");
// and so on
}
Alternatively, if you can find a C# "eval" method, you can evaluate the expression directly (and you can also use True/False instead of 0/1).
Edit:
Found a simple tokenizer that will probably work for parsing the test equations:
using System;
using System.Text.RegularExpressions;
public static string[] Tokenize(string equation)
{
Regex RE = new Regex(#"([\(\)\! ])");
return (RE.Split(equation));
}
//from here: https://www.safaribooksonline.com/library/view/c-cookbook/0596003390/ch08s07.html
Edit 2:
Just wrote a sample project that does it.
//this parses out the string input, does not use the classifications
List<string> members = new List<string>();
string input = "Customers: David, Danny, Mike, Luke. Car: BMW";
string[] t1 = input.Split(new string[] {". "}, StringSplitOptions.RemoveEmptyEntries);
foreach (String t in t1)
{
string[] t2 = t.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
string[] t3 = t2[1].Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
foreach (String s in t3)
{
members.Add(s.Trim());
}
}
This tokenizes the equation and replaces with 1 and 0.
string eq = "(Danny || Jennifer) && (!BMW)";
Regex RE = new Regex(#"([\(\)\! ])");
string[] tokens = RE.Split(eq);
string eqOutput = String.Empty;
string[] operators = new string[] { "&&", "||", "!", ")", "("};
foreach (string tok in tokens)
{
if (tok.Trim() == String.Empty)
continue;
if (operators.Contains(tok))
{
eqOutput += tok;
}
else if (members.Contains(tok))
{
eqOutput += "1";
}
else
{
eqOutput += "0";
}
}
At this point, the equation "(Danny || Jennifer) && (!BMW)" looks like "(1||0)&&(!1)".
Now reduce the equation to a 1 or 0.
while (eqOutput.Length > 1)
{
if (eqOutput.Contains("!1"))
eqOutput = eqOutput.Replace("!1", "0");
else if (eqOutput.Contains("!0"))
eqOutput = eqOutput.Replace("!0", "1");
else if (eqOutput.Contains("1&&1"))
eqOutput = eqOutput.Replace("1&&1", "1");
else if (eqOutput.Contains("1&&0"))
eqOutput = eqOutput.Replace("1&&0", "0");
else if (eqOutput.Contains("0&&1"))
eqOutput = eqOutput.Replace("0&&1", "0");
else if (eqOutput.Contains("0&&0"))
eqOutput = eqOutput.Replace("0&&0", "0");
else if (eqOutput.Contains("1||1"))
eqOutput = eqOutput.Replace("1||1", "1");
else if (eqOutput.Contains("1||0"))
eqOutput = eqOutput.Replace("1||0", "1");
else if (eqOutput.Contains("0||1"))
eqOutput = eqOutput.Replace("0||1", "1");
else if (eqOutput.Contains("0||0"))
eqOutput = eqOutput.Replace("0||0", "0");
else if (eqOutput.Contains("(1)"))
eqOutput = eqOutput.Replace("(1)", "1");
else if (eqOutput.Contains("(0)"))
eqOutput = eqOutput.Replace("(0)", "0");
}
Now you should have a string that contains only a 1 or a 0 indicating true or false, respectively.
With the help of DynamicExpresso you can easily do this in 10 lines. Let's say the text and the user input are like this:
var text = "Bob and Tom are in the same class.";
var input = "(Bob || Alice) && Tom";
You can consider "Bob" "Alice" "Tom" are variables whose type is bool in C#, the user input string becomes a valid C# expression, evaulate it using DynamicExpresso and get a bool result.
var variables = input.Split(new[] { "(", "||", "&&", ")", " " },
StringSplitOptions.RemoveEmptyEntries);
var interpreter = new Interpreter();
foreach (var variable in variables)
{
interpreter.SetVariable(variable, text.Contains(variable));
}
var result = (bool)interpreter.Parse(input).Invoke();

Using || operator in LinQ

I've a small example to use || operator with Where() but something may be wrong:
var list = new List<string>
{
"One",
"Two",
"Three"
};
string s = "One";
var numbers = list.Where(x => x == s || !string.IsNullOrEmpty(x));
foreach(var number in numbers)
{
Console.WriteLine(number);
// output:
// One
// Two
// Three
}
s = null;
numbers = list.Where(x => x == s || !string.IsNullOrEmpty(x));
foreach(var number in numbers)
{
Console.WriteLine(number);
// output:
// One
// Two
// Three
}
In the first case, why was !string.IsNullOrEmpty(x) still checked when we had x == s true?
I understood:
if (A && B)
{
// we need A and B are true
}
if (A || B)
{
// we need A is true or B is true
// if A is true, no ned to check B is true or not
}
So, my question is: what did I misunderstand?
You are right in saying that:
a || b
Will not evaluate b if a is true, but:
Where LINQ using Lambda expression checks every element in the Enumerable regardless of the previous result. Thus when you do:
string s = "One";
var numbers = list.Where(x => x == s || !string.IsNullOrEmpty(x));
It checks every element in the query whenever the Where lambda expression is valid:
x == s || !string.IsNullOrEmpty(x)); //x = "One", x == s is true
x == s || !string.IsNullOrEmpty(x)); //x = "Two", !string.IsNullOrEmpty(x) is true
x == s || !string.IsNullOrEmpty(x)); //x = "Three", !string.IsNullOrEmpty(x) is true
Thus you got all the elements.
Consider using TakeWhile if you want to stop taking the query result as soon as a condition is no longer reached.
var numbers = list.Where(x => x == s || !string.IsNullOrEmpty(x)); takes each element from list - x and checks if it fits specific condition.
The condition is x == s OR !string.IsNullOrEmpty(x), so element should fit at least one part of the condition.
Particularly, every element of list meets the !string.IsNullOrEmpty(x) condition.
Try to add null to your list. It doesn't meet the !string.IsNullOrEmpty(x) and doesn't meet x == s, so it won't be included in result.
var list = new List<string>
{
"One",
"Two",
"Three",
null
};
var numbers = list.Where(x => x == "One" || !string.IsNullOrEmpty(x)).ToList();
The operator is correct . In your first example:
string s = "One";
var numbers = list.Where(x => x == s || !string.IsNullOrEmpty(x));
foreach(var number in numbers)
{
Console.WriteLine(number);
// output:
// One <-- First condition is met
// Two <-- First condition is not met so goes into the OR operator and returns true
// Three <--Same as above
}
https://msdn.microsoft.com/en-us/library/6373h346.aspx

Retrieve the name of the column from which the values where chosen in C#

I have a form which has 4 columns say Col1,Col2,Col2,Col4...
Each Column has a combo box (cmb1,cmb2,cmb3,cmb4) having values ranged from 1 to 3.
If I select value of cmb1 as 1,
cmb2 as 2,
cmb3 as 3,
cmb4 as 2 ....
I need to know which column had 1 as value,2 as value and 3 .
here the result should be like
Col1 has 1 value ,
Col2 and Col4 has 2 value and
Col3 has 3 value
Following is my code :
if (cmb1 == "1" && cmb2 == "1" && cmb3 == "1" && cmb4 == "1")
{
Console.WriteLine("Col1,Col2,Col3,Col4");
}
if (cmb1 == "1" && cmb2 == "1" && cmb3 == "1")
{
Console.WriteLine("Col1,Col2,Col3");
}
if (cmb1 == "2" && cmb2 == "2" )
{
Console.WriteLine("Col1,Col2");
}
This code is too lengthy .Which is the best way with minimum lines of code.
You can group by the value, then select the column name by Linq.
For display you can use string.Join().
var cmb1 = "1";
var cmb2 = "2";
var cmb3 = "3";
var cmb4 = "2";
var selection = new Dictionary<string, string>()
{
{"Col1", cmb1},
{"Col2", cmb2},
{"Col3", cmb3},
{"Col4", cmb4},
};
var result = selection
.GroupBy(i => i.Value) // Group by your combo box values
.Select(group =>
new
{
Value = group.Key,
Columns = group.Select(i => i.Key).ToArray()
}
);
foreach (var item in result) // for each value in your combo box
{
Console.WriteLine(
string.Format("Value: {0}, Columns: {1}",
item.Value,
string.Join(",", item.Columns)));
string[] column = item.Columns; // It should store somewhere else, line for demo only
}
ComboBox has property named SelectedItem, you can get the selectedvalue due to SelectedItem.And set the Name of Combox.
List<Combox> comboxs = new List<Combox>;
comboxs.Add(cmb1);
comboxs.Add(cmb2);
comboxs.Add(cmb3);
comboxs.Add(cmb4);
foreach(var combox in comboxs){
Console.WriteLine(combox.Name + "has" + combox.SelectedItem + "value");
}

In C#, what is the simplest way to calculate "trend" given a current and previous status?

I have a variable to show RAG Status (Red, Amber, Green) on a project
var previousStatus = "R"
var currentStatus = "A"
and i am trying to calculate "Trend" so sometihng like
var trend = CalculateTrend(previous, current)
I am trying to find a more elegant solution than
if (prev == current)
return "Stable";
if (prev == "R" && (current == "G" ||current == "A"))
return "Improving";
if (prev == "G" && (current == "R" ||current == "A"))
return "Declining";
if (prev == "A" && current == "G")
return "Improving";
if (prev == "A" && current == "R")
return "Declining";
any suggestion on a "cleaner" solution.
Create an enum with an integer value for each status.
public enum Status
{
Red = 1,
Amber = 2,
Green = 3
}
Then use int.CompareTo method.
switch(previous.CompareTo(current))
{
case -1:
return "Improving";
case 0:
return "Stable";
case 1:
return "Declining";
}
Use a numeric system. Rate the values with equivalent numeric values. Then you can use math.
If you just want to avoid the if statements you can create a simple lookup dictionary:
private static string GetTrend(string prev, string cur)
{
var trends = new Dictionary<string, string[]>()
{
{"Stable", new[] {"AA", "RR", "GG"}},
{"Improving", new[] {"RG", "RA", "AG"}},
{"Declining", new[] {"GA", "GR", "AR"}},
};
return trends.Single(x => x.Value.Contains(prev + cur)).Key;
}

Categories

Resources