C# Multiple strings in a if-statment - c#

I'm trying to check if a user input matches a few already known values. How do I do this in C#?
I've tried this:
if (UserInput.Text == "2", "4", "8", "16", "32")
{ do things
}
else
{
do other things
}
And a couple of other signs between my strings. Is it possible to check against all my strings or do I have to set up a seperate if-statment for all my strings?

You can use a switch to compare a string to multiple values:
switch (UserInput.Text) {
case "2":
case "4":
case "8":
case "16":
case "32":
// do things
break;
default:
// do other things
break;
}
You can put the strings in a hash set, and check if the hash set contains the user input:
HashSet<string> strings = new HashSet<string>();
strings.Add("2");
strings.Add("4");
strings.Add("8");
strings.Add("16");
strings.Add("32");
if (strings.Contains(UserInput.Text)) {
// do things
} else {
// do other things
}

You could use an array:
string[] validValues = new string[] {"2", "4", "8", "16", "32"}
if (validValues.Contains( UserInput.Text))
{ do things
}
else
{
do other things
}
This way you get a nice, readable sollution.

I like extensions methods for these situations
public static class StringExtensions
{
public static int MatchWord(this string container, bool caseInsensitive, params string[] values)
{
int result = -1;
int counter = 0;
foreach (string s in values)
{
if (s != null && string.Compare(container, s, caseInsensitive) == 0)
{
result = counter;
break;
}
counter++;
}
return result;
}
}
Now you could write (whenever you need it)
int matchIndex = UserInput.Text.MatchWord(false, "2", "4", "8", "16", "32");
if(matchIndex != -1)
{
// string is equal to one of the input
}
else
{
}
but you could also use this extension for
int matchIndex = UserInput.Text.MatchWord(true, "john", "ron", "mark", "james", "bob");
If you don't need the index of the matched word, you could simplify everything using a boolean for the return value of the extension method

You could make an array of what you want to check against and just check if the array contains an elements that is the same as UserInput.Text.
Want a code example?

I know the following solution is not good. But I am trying to do the same with If statement
if (UserInput.Text == "2"|| UserInput.Text =="4"||UserInput.Text == "16")
{ do things
}
else
{
do other things
}

Related

How can I make loop instead of switch statement?

How can I write this shorter? For each case I have to write this and then It is too long because there are 48 numbers so I need 48 cases. Is there a way to make a loop?
switch (ballBounce.ToString())
{
case "1":
if (ballBounce == n0)
{
textBox1.Text = number.ToString();
}
break;
case "2":
if (ballBounce == n1)
{
textBox1.Text = number.ToString();
}
break;
case "3":
if (ballBounce == n2)
{
textBox1.Text = number.ToString();
}
break; ...
The loop is useless in this case.
You can use dictionary.
private Dictinoary<string, string> cases = new Dictionary<string, string> {
{"1", "one"},
{"2", "two"},
// ...
};
// in some method
string text;
if (cases.TryGetValue(ballBounce.ToString(), out text)){
this.textBox1.Text = text;
}
If you want something smarter than simple value, you can have functions in the dictionary.
private Dictinoary<string, Func<string>> cases = new Dictionary<string, Func<string>> {
{"1", () => "one"},
{"2", () =>
{
if (DateTime.Now.Seconds % 2 == 0) { return "A"; }
else { return "B"; }
}},
// ...
};
// in some method
Func<string> textProvider;
if (cases.TryGetValue(ballBounce.ToString(), out textProvider)){
this.textBox1.Text = textProvider();
}
Based on your ToString()'s, I'm assuming that ballBounce is an int.
if (ballBounce <= 48 && ballBounce > 0)
{
textBox1.Text = ballBounce.ToString();
}
why do you use if with case?
you don't need to check twice.
also if this is the code for every case
textBox1.Text = number.ToString();
then you don't need switch or if
jsut write textBox1.Text = number.ToString(); and you are good to go.
also if you have some cases ony you can do it that way:
switch (ballBounce.ToString())
{
case "1":
case "2":
case"3":
//....
textBox1.Text = number.ToString();
}

Check if string has some special characters in C# [duplicate]

I want to check if a String s, contains "a" or "b" or "c", in C#.
I am looking for a nicer solution than using
if (s.contains("a")||s.contains("b")||s.contains("c"))
Well, there's always this:
public static bool ContainsAny(this string haystack, params string[] needles)
{
foreach (string needle in needles)
{
if (haystack.Contains(needle))
return true;
}
return false;
}
Usage:
bool anyLuck = s.ContainsAny("a", "b", "c");
Nothing's going to match the performance of your chain of || comparisons, however.
Here's a LINQ solution which is virtually the same but more scalable:
new[] { "a", "b", "c" }.Any(c => s.Contains(c))
var values = new [] {"abc", "def", "ghj"};
var str = "abcedasdkljre";
values.Any(str.Contains);
If you are looking for single characters, you can use String.IndexOfAny().
If you want arbitrary strings, then I'm not aware of a .NET method to achieve that "directly", although a regular expression would work.
You can try with regular expression
string s;
Regex r = new Regex ("a|b|c");
bool containsAny = r.IsMatch (s);
If you need ContainsAny with a specific StringComparison (for example to ignore case) then you can use this String Extentions method.
public static class StringExtensions
{
public static bool ContainsAny(this string input, IEnumerable<string> containsKeywords, StringComparison comparisonType)
{
return containsKeywords.Any(keyword => input.IndexOf(keyword, comparisonType) >= 0);
}
}
Usage with StringComparison.CurrentCultureIgnoreCase:
var input = "My STRING contains Many Substrings";
var substrings = new[] {"string", "many substrings", "not containing this string" };
input.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// The statement above returns true.
”xyz”.ContainsAny(substrings, StringComparison.CurrentCultureIgnoreCase);
// This statement returns false.
This is a "nicer solution" and quite simple
if(new string[] { "A", "B", ... }.Any(s=>myString.Contains(s)))
List<string> includedWords = new List<string>() { "a", "b", "c" };
bool string_contains_words = includedWords.Exists(o => s.Contains(o));
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
{
return needles.Any(haystack.Contains);
}
As a string is a collection of characters, you can use LINQ extension methods on them:
if (s.Any(c => c == 'a' || c == 'b' || c == 'c')) ...
This will scan the string once and stop at the first occurance, instead of scanning the string once for each character until a match is found.
This can also be used for any expression you like, for example checking for a range of characters:
if (s.Any(c => c >= 'a' && c <= 'c')) ...
// Nice method's name, #Dan Tao
public static bool ContainsAny(this string value, params string[] params)
{
return params.Any(p => value.Compare(p) > 0);
// or
return params.Any(p => value.Contains(p));
}
Any for any, All for every
static void Main(string[] args)
{
string illegalCharacters = "!##$%^&*()\\/{}|<>,.~`?"; //We'll call these the bad guys
string goodUserName = "John Wesson"; //This is a good guy. We know it. We can see it!
//But what if we want the program to make sure?
string badUserName = "*_Wesson*_John!?"; //We can see this has one of the bad guys. Underscores not restricted.
Console.WriteLine("goodUserName " + goodUserName +
(!HasWantedCharacters(goodUserName, illegalCharacters) ?
" contains no illegal characters and is valid" : //This line is the expected result
" contains one or more illegal characters and is invalid"));
string captured = "";
Console.WriteLine("badUserName " + badUserName +
(!HasWantedCharacters(badUserName, illegalCharacters, out captured) ?
" contains no illegal characters and is valid" :
//We can expect this line to print and show us the bad ones
" is invalid and contains the following illegal characters: " + captured));
}
//Takes a string to check for the presence of one or more of the wanted characters within a string
//As soon as one of the wanted characters is encountered, return true
//This is useful if a character is required, but NOT if a specific frequency is needed
//ie. you wouldn't use this to validate an email address
//but could use it to make sure a username is only alphanumeric
static bool HasWantedCharacters(string source, string wantedCharacters)
{
foreach(char s in source) //One by one, loop through the characters in source
{
foreach(char c in wantedCharacters) //One by one, loop through the wanted characters
{
if (c == s) //Is the current illegalChar here in the string?
return true;
}
}
return false;
}
//Overloaded version of HasWantedCharacters
//Checks to see if any one of the wantedCharacters is contained within the source string
//string source ~ String to test
//string wantedCharacters ~ string of characters to check for
static bool HasWantedCharacters(string source, string wantedCharacters, out string capturedCharacters)
{
capturedCharacters = ""; //Haven't found any wanted characters yet
foreach(char s in source)
{
foreach(char c in wantedCharacters) //Is the current illegalChar here in the string?
{
if(c == s)
{
if(!capturedCharacters.Contains(c.ToString()))
capturedCharacters += c.ToString(); //Send these characters to whoever's asking
}
}
}
if (capturedCharacters.Length > 0)
return true;
else
return false;
}
You could have a class for your extension methods and add this one:
public static bool Contains<T>(this string s, List<T> list)
{
foreach (char c in s)
{
foreach (T value in list)
{
if (c == Convert.ToChar(value))
return true;
}
}
return false;
}
You can use Regular Expressions
if(System.Text.RegularExpressions.IsMatch("a|b|c"))
If this is for a password checker with requirements, try this:
public static bool PasswordChecker(string input)
{
// determins if a password is save enough
if (input.Length < 8)
return false;
if (!new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R",
"S", "T", "U", "V", "W", "X", "Y", "Z", "Ä", "Ü", "Ö"}.Any(s => input.Contains(s)))
return false;
if (!new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}.Any(s => input.Contains(s)))
return false;
if (!new string[] { "!", "'", "§", "$", "%", "&", "/", "(", ")", "=", "?", "*", "#", "+", "-", "_", ".",
",", ";", ":", "`", "´", "^", "°", }.Any(s => input.Contains(s)))
return false;
return true;
}
This will set a password to have a min length of 8, have it use at least one uppercase char, at least one number, and at least one of the special chars

Test for all possibilities in a string

I am trying to test (compare against another value in memory) for all possible combinations in a string but wanted to know what the best way is to do it.
My input string is 0246, the trick is that each number can be one of 2 options, for instance:
[0,1][2,3][4,5][6,7]
I want to be able to flip through all possible combinations, it's kind of like cracking a safe but that is not the purpose of this, I promise!
I was thinking of doing a foreach loop to switch through each option but my loops would be nested and I know performance will take a hit, since Linq is like the new black, can this be done using that?
UPDATE*
I want the result to return in order from low to high as my original string that I am comparing against could be 0001 but doesn't make sense to randomly jump around.
I also want to keep track of how many times I had to generate a different variation of this and note that down as it will be used at a later time.
Do you mean this:
var allCombinations = from a in new[] { "0", "1", }
from b in new[] { "2", "3", }
from c in new[] { "4", "5", }
from d in new[] { "6", "7", }
select a + b + c + d;
Or more fancily:
var allCombinations = from a in "01"
from b in "23"
from c in "45"
from d in "67"
select string.Concat(a, b, c, d);
In the latter (fancy) version a, b, c and d are char variables, and string.Concat(a, b, c, d) could also be written a.ToString() + b + c + d.
Here's an approach that works for any number of inputs (after parsing your format into int[][]), using Aggregate and Join:
var data = new[]
{
new[] { 0, 1 },
new[] { 2, 3 },
new[] { 4, 5 },
new[] { 6, 7 },
};
var nums = data.Aggregate(new[] { "" }.AsEnumerable(),
(agg, arr) => agg.Join(arr, x => 1, x => 1, (i, j) => i.ToString() + j));
Outputs:
0246
0247
0256
0257
0346
0347
0356
0357
1246
1247
1256
1257
1346
1347
1356
1357
It uses LINQ, so it's probably not the fastest thing ever (still < 1 ms for me with this data), and something smells about how I'm using Join with fixed join values, so it's probably not the best thing ever, but hey - it works.
I'm assuming you actually need all the values listed out. If all you're really trying to do is see if the value matches something that looks like a valid passcode, a regex like Dmitry's solution is probably the way to go.
To test the value you have im memory you don't need to generate all possible values. Generating full string and compairing it is the worse way to do this job.
If you want to control the process of compairing (count operations) you can't use any built-in methods(regular expressions or Linq). You should manually go through all the chars in string and check them.
public bool Test(string input, string[] possibleValues)
{
int operationsCount = 0;
if (input.Length != possibleValues.Length)
{
return false;
}
for (int i = 0; i < input.Length; i++)
{
bool found = false;
for (int j = 0; j < possibleValues[i].Length; j++)
{
operationsCount++;
if (input[i] == possibleValues[i][j])
{
found = true;
break;
}
}
if (!found)
{
Console.WriteLine("Value does not satisfies the condition. Number of operations: " + operationsCount);
return false;
}
}
Console.WriteLine("Value satisfies the condition. Number of operations: " + operationsCount);
return true;
}
Test("0247", new string[] { "01", "23", "45", "67" });
The shortest way is to can use Regular expression to check if the input string satisfies the condition. Regular expressions are build for matching strings to specific pattert. The only problem in this solution: you can not determine how many operations you made.
public bool Test(string input, string[] possibleValues)
{
String pattern = GeneratePattern(possibleValues);
bool result = Regex.IsMatch(input, pattern);
if (!result)
{
Console.WriteLine("Value does not satisfies the condition.");
}
else
{
Console.WriteLine("Value satisfies the condition.");
}
return result;
}
private string GeneratePattern(string[] possibleValues)
{
StringBuilder sb = new StringBuilder();
sb.Append("^");
foreach (var possibleValue in possibleValues)
{
sb.Append("[");
sb.Append(possibleValue);
sb.Append("]");
}
sb.Append("$");
return sb.ToString();
}

I need to replace a C# switch with something more compact

I have the following code:
switch (pk.Substring(2, 2))
{
case "00":
ViewBag.Type = _reference.Get("14", model.Type).Value;
break;
case "01":
ViewBag.Type = _reference.Get("18", model.Type).Value;
break;
}
It does the job but does not look very clean to me. Is there some way I could make this code a bit smaller. I was thinking to just have the number 14 or 18 as a variable but I am not sure the best way to code if I should use if-else or some other way.
You could use a static dictionary as a map instead of a switch-statement.
static readonly Dictionary<string, string> map = new Dictionary<string, string> {
{ "00", "14" },
{ "01", "18" },
// ... more ...
};
// ... in your method ...
string str = pk.Substring(2, 2);
string val;
if (!map.TryGetValue(str, out val))
{
// Handle error, like in the "default:" case of the switch statement
}
else
{
ViewBag.Type = _reference.Get(val, model.Type).Value;
}
However, I would only do this, if there are really a lot of mappings that maybe can even be "read" from an external source like a configuration file.
Also note, that if the "key" is really a consecutive sequence of integers starting at 0, you might be able to use an array, where the "key" is simply the index into it.
static readonly string[] map = new string[] {
"14", "18", ...
};
int index = Int32.Parse(pk.Substring(2, 2)); // Error handling elided.
if (index < 0 || index > map.Length)
{
// Handle error, like in the "default:" case of the switch statement
}
else
{
ViewBag.Type = _reference.Get(map[index], model.Type).Value;
}
Otherwise rather stay with an explicit switch statement (possibly factoring out the assignment for more terse code):
string val;
switch (pk.Substring(2, 2))
{
case "00":
val = "14";
break;
case "01":
val = "18";
break;
// ... more ...
default:
// Error handling for unknown switch-value.
break;
}
ViewBag.Type = _reference.Get(val, model.Type).Value;
It seems that there is some relationship between "00"->"14" and "01"->"18". I believe this relationship results from the business logic. You should wrap the logic and make the code in your controller clear. Finally the code in the controller should look like:
public ActionResult MyAction()
{
//some code
ViewBag.Type = TypeProvider.GetType(pk, model.Type);
//return something
}
class TypeProvider
{
Dictionary<string, string> relations = ...
//a dictionary stores "00"->"14" logics
public static SomeType GetType(string pk, Type modelType)
{
return _reference.Get(relations[pk.SubString(2,2)], modelType).Value;
}
}
var data = pk.Substring(2, 2);
var choice = data == "00" ? "14" : (data=="01"?"18":"");
if (choice != string.Empty) ViewBag.Type = _reference.Get(choice, model.Type).Value;
I use mapping extensions fot that kind of code:
ViewBag.Type = pk.Substring(2, 2)
.Map("00", x => GetViewBagValue("14"))
.Map("01", x => GetViewBagValue("18"))
and in your case this method:
private ViewBagValue GetViewBagValue(string value)
{
return _reference.Get(value, model.Type).Value;
}
I use this. You could easily change it to generic or use e.g. object[] instead. Not super efficient, but very compact:
public static class Util {
public static string Switch(string value, params string[] nameValues) {
for (int x = 0; x < nameValues.Length; x += 2) {
if (nameValues[x] == value) {
return nameValues[x + 1];
}
}
return string.Empty;
}
}
Then just call that like this:
var res = Util.Switch("test2", "test1", "res1", "test2", "res2");
Best of luck!

Custom sort of a string array non-alphabetical

I have a string array like this:
string[] names = new string[] { "john", "paul", "ringo", "george", "janis" };
I want to sort this array using a custom criteria. It can't be alphabetical. It might be in this order: pgrj.
I've tried to implement a new IComparer, but inside the Compare() method I can't use string.Compare cause it would sort alphabetically and I don't want to do that.
The question is: How can I sort the names array in this order: pgrj ? In the 'j' case. Janis might be before John.
Thanks.
I would make an array of the letters of the alphabet, in the order that they should be sorted. Let's call this array sort. You could then do something like
for (int i = 0; i < s1.Length; i++)
{
int s1Value = sort.IndexOf(s1[i]);
int s2Value = sort.IndexOf(s2[i]);
if(s1Value > s2Value)
return 1;
if(s2Value > s1Value)
return -1;
}
return 0;
Now a few disclaimers.
I might have my -1 and 1 mixed up. I haven't looked at ICompare in a while and I forget which is which.
This does not handle the two strings being different lengths.
I have not tested this code.
You could improve on this by making a custom class to assign a weight to each character.
class CustomAlphabetSort
{
public char Character { get; set; }
public int Weight { get; set; }
}
From here you can sum of the value for each letter of a string and do the comparison that way. It might be a little more complex than your situation requires
void Main()
{
string[] names = new string[] { "john", "paul", "ringo", "george", "janis" };
var reorderedNames = names.OrderByDescending(x => x, new MyComparer());
}
class MyComparer : IComparer<string>{
int IComparer<string>.Compare(string s1, string s2){
char l1 = s1[0];
char l2 = s2[0];
int ret;
switch(l1){
case 'g': if(l2 == 'p'){
return -1;
}
else{
goto default;
}
case 'r': if(l2 == 'p' || l2 == 'g'){
return -1;
}
else{
goto default;
}
case 'j': if(l2 == 'p' || l2 == 'g' || l2 == 'r'){
return -1;
}
else{
goto default;
}
default: ret = (l2 != l1) ? 1 : s1.CompareTo(s2); return ret;
}
return ret;
}
};

Categories