How to make your if shorter? - c#

I understood that when using Regex I can enter the value | to search for many values. For example:
Regex sabrina = new Regex("Rihanna|rihanna|Sabrina|sabrina");
I have a string which I want to compare to other values, so I use if like this:
if (rihanna == "Rihanna" || rihanna == "sabrina")
My question is if it possible to make the if shorter? I know this code is not working but what I'm looking for something like this:
if (rihanna == "Rihanna|sabrina")

Single line solution:
if("Rihanna|rihanna|Sabrina|sabrina".Split(new[] {'|'}).Contains(rihanna))
or without String.Split method usage:
if ((new[] { "Rihanna", "rihanna", "Sabrina", "sabrina" }).Contains(rihanna))
If that kind of check is performed more than once you should save string[] array of possible values into a variable:
var names = new[] { "Rihanna", "rihanna", "Sabrina", "sabrina" };
if(names.Contains(rihanna))

You could use a List<string> along with the Enumerable.Contains method.
Example:
var values = new List<string> { "Rihanna", "rihanna", "Sabrina", "sabrina" };
if (values.Contains(rihanna))
{
// etc.
}
The if statement is now a lot more concise, and you can add more items to your list quickly and easily. If you're performing this operation frequently, you should move the declaration of the list to a member variable in the containing class so that you don't incur the overhead of list initialization every time this method is called.
An even better solution would be to use Enumerable.Any and String.Equals to perform a case-insensitive comparison:
if (values.Any(x => String.Equals(rihanna, x, StringComparison.OrdinalIgnoreCase))
{
// your code here
}
Although the if statement is now longer, the solution is much more robust.

If you're looking for easier maintenance of a potentially long list of string candidates, why not use a switch statement? Technically it will be "longer" character-wise, but if you have to modify things down the road, or provide some subtle secondary processing, it could make things a lot easier.

As an alternative to the above answers, perhaps you could consider using an extension method:
public static bool EqualsAny(this string input, params string[] values)
{
return values.Any(v => String.Equals(input, v, StringComparison.OrdinalIgnoreCase));
}
With usage like:
if (rihanna.EqualsAny("Rihanna", "Sabrina"))
This should give pretty readable/compact/short if comparisons for you, especially in comparison to some of the other alternatives here.
Tweak the EqualsAny check if you want to have the OrdinalIgnoreCase or not or feel free to add any overloads you wish. Could even implement the whole piping/splitting where you'd pass in "Rihanna|Sabrina".
EDIT: Perhaps more critically, it centralizes how you compare rather than duplicating the code everywhere.

You can use your own Regex and use it as a single line..
if (Regex.Match(rihanna, "Rihanna|rihanna|Sabrina|sabrina").Success)
Or make it case-insensative like this..
if (Regex.Match(rihanna, "rihanna|sabrina", RegexOptions.IgnoreCase).Success){

Ignore casing, which looks like something you're going for, and use String.Compare:
if(String.Compare(rihanna, "sabrina", StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(rihanna, "rihana", StringComparison.OrdinalIgnoreCase) == 0 ) {
// do stuff
}

Dictionary or HashSet (potentially with case insensitive check on names) is another approach which will give you better performance if you have more than several items and repeat checks often.
var listToCheck = new Dictionary<string, string>(
StringComparer.CurrentCultureIgnoreCase) { { "rihanna", null}};
if (listToCheck.ContainsKey("Rihanna")) ....

Related

if check nesting c sharp [duplicate]

Any easier way to write this if statement?
if (value==1 || value==2)
For example... in SQL you can say where value in (1,2) instead of where value=1 or value=2.
I'm looking for something that would work with any basic type... string, int, etc.
How about:
if (new[] {1, 2}.Contains(value))
It's a hack though :)
Or if you don't mind creating your own extension method, you can create the following:
public static bool In<T>(this T obj, params T[] args)
{
return args.Contains(obj);
}
And you can use it like this:
if (1.In(1, 2))
:)
A more complicated way :) that emulates SQL's 'IN':
public static class Ext {
public static bool In<T>(this T t,params T[] values){
foreach (T value in values) {
if (t.Equals(value)) {
return true;
}
}
return false;
}
}
if (value.In(1,2)) {
// ...
}
But go for the standard way, it's more readable.
EDIT: a better solution, according to #Kobi's suggestion:
public static class Ext {
public static bool In<T>(this T t,params T[] values){
return values.Contains(t);
}
}
C# 9 supports this directly:
if (value is 1 or 2)
however, in many cases: switch might be clearer (especially with more recent switch syntax enhancements). You can see this here, with the if (value is 1 or 2) getting compiled identically to if (value == 1 || value == 2).
Is this what you are looking for ?
if (new int[] { 1, 2, 3, 4, 5 }.Contains(value))
If you have a List, you can use .Contains(yourObject), if you're just looking for it existing (like a where). Otherwise look at Linq .Any() extension method.
Using Linq,
if(new int[] {1, 2}.Contains(value))
But I'd have to think that your original if is faster.
Alternatively, and this would give you more flexibility if testing for values other than 1 or 2 in future, is to use a switch statement
switch(value)
{
case 1:
case 2:
return true;
default:
return false
}
If you search a value in a fixed list of values many times in a long list, HashSet<T> should be used. If the list is very short (< ~20 items), List could have better performance, based on this test
HashSet vs. List performance
HashSet<int> nums = new HashSet<int> { 1, 2, 3, 4, 5 };
// ....
if (nums.Contains(value))
Generally, no.
Yes, there are cases where the list is in an Array or List, but that's not the general case.
An extensionmethod like this would do it...
public static bool In<T>(this T item, params T[] items)
{
return items.Contains(item);
}
Use it like this:
Console.WriteLine(1.In(1,2,3));
Console.WriteLine("a".In("a", "b"));
You can use the switch statement with pattern matching (another version of jules's answer):
if (value switch{1 or 3 => true,_ => false}){
// do something
}
Easier is subjective, but maybe the switch statement would be easier? You don't have to repeat the variable, so more values can fit on the line, and a line with many comparisons is more legible than the counterpart using the if statement.
In vb.net or C# I would expect that the fastest general approach to compare a variable against any reasonable number of separately-named objects (as opposed to e.g. all the things in a collection) will be to simply compare each object against the comparand much as you have done. It is certainly possible to create an instance of a collection and see if it contains the object, and doing so may be more expressive than comparing the object against all items individually, but unless one uses a construct which the compiler can explicitly recognize, such code will almost certainly be much slower than simply doing the individual comparisons. I wouldn't worry about speed if the code will by its nature run at most a few hundred times per second, but I'd be wary of the code being repurposed to something that's run much more often than originally intended.
An alternative approach, if a variable is something like an enumeration type, is to choose power-of-two enumeration values to permit the use of bitmasks. If the enumeration type has 32 or fewer valid values (e.g. starting Harry=1, Ron=2, Hermione=4, Ginny=8, Neville=16) one could store them in an integer and check for multiple bits at once in a single operation ((if ((thisOne & (Harry | Ron | Neville | Beatrix)) != 0) /* Do something */. This will allow for fast code, but is limited to enumerations with a small number of values.
A somewhat more powerful approach, but one which must be used with care, is to use some bits of the value to indicate attributes of something, while other bits identify the item. For example, bit 30 could indicate that a character is male, bit 29 could indicate friend-of-Harry, etc. while the lower bits distinguish between characters. This approach would allow for adding characters who may or may not be friend-of-Harry, without requiring the code that checks for friend-of-Harry to change. One caveat with doing this is that one must distinguish between enumeration constants that are used to SET an enumeration value, and those used to TEST it. For example, to set a variable to indicate Harry, one might want to set it to 0x60000001, but to see if a variable IS Harry, one should bit-test it with 0x00000001.
One more approach, which may be useful if the total number of possible values is moderate (e.g. 16-16,000 or so) is to have an array of flags associated with each value. One could then code something like "if (((characterAttributes[theCharacter] & chracterAttribute.Male) != 0)". This approach will work best when the number of characters is fairly small. If array is too large, cache misses may slow down the code to the point that testing against a small number of characters individually would be faster.
Using Extension Methods:
public static class ObjectExtension
{
public static bool In(this object obj, params object[] objects)
{
if (objects == null || obj == null)
return false;
object found = objects.FirstOrDefault(o => o.GetType().Equals(obj.GetType()) && o.Equals(obj));
return (found != null);
}
}
Now you can do this:
string role= "Admin";
if (role.In("Admin", "Director"))
{
...
}
public static bool EqualsAny<T>(IEquatable<T> value, params T[] possibleMatches) {
foreach (T t in possibleMatches) {
if (value.Equals(t))
return true;
}
return false;
}
public static bool EqualsAny<T>(IEquatable<T> value, IEnumerable<T> possibleMatches) {
foreach (T t in possibleMatches) {
if (value.Equals(t))
return true;
}
return false;
}
I had the same problem but solved it with a switch statement
switch(a value you are switching on)
{
case 1:
the code you want to happen;
case 2:
the code you want to happen;
default:
return a value
}

What is a smart way to check if a string variable value is one of a specified set of value in C#?

I am writing a simple C#.NET application where I have an if condition where I am checking if a string variable value is a string or another string or another string or another one, etcetc.
Something like this:
if(protocollo == "2019/0002391" || protocollo == "2019/0002390" || protocollo == "2019/0001990" || ........)
This solution works but it is not so elegant. What could be a smarter way to implement the same behavior?
I agree with #JeroenMostert that it really depends on the context of the rest of your application. That said, using an array of strings and checking if your string is in there is a nice straightforward solution. There are certianily solutions that would scale better, take a look at HashSet.
string[] s = new string[] { "2019/0002391", "2019/0002390", "2019/0001990", ... };
if (s.Contains(protocollo)) {
// fill in here
}
You never said, so I'm making the assumption that the strings you're checking against is hard-coded and not something that changes often. To that end, you could create a string[] or HashSet<string> in a static class so it only initializes the one time, then expose a method for checking a second string against the valid ones.
void Main()
{
Console.WriteLine(Protocols.ValidProtocol("2019/0002391")); //True
Console.WriteLine(Protocols.ValidProtocol("2018/0000000")); //False
}
// Define other methods and classes here
public static class Protocols
{
public static bool ValidProtocol(string protocol)
{
return _validProtocols.Contains(protocol);
}
private static readonly HashSet<string> _validProtocols = new HashSet<string>
{
"2019/0002391",
"2019/0002390",
"2019/0001990"
//etc, etc...
};
}
A solution like this would probably not be ideal if the list of strings you need to check against changes often. You'd probably want to pull the list from an external source like a file or a database if you need to modify it often.
I had some code similar to your example in a static extension method. I didn't want to have to instantiate an array every time the method was called, but I wanted to improve the readability of the code.
I improved the code using the switch expression which was added in C# 8. Here is the what your example might look like if implemented with a switch expression. Depending on what your code does if the condition is true you may be able to improve on this, but this is the basics.
var isProtocolloMatch = protocollo switch
{
"2019/0002391" => true,
"2019/0002390" => true,
"2019/0001990" => true,
_ => false
};
if (isProtocolloMatch)
{
// do stuff
}

Is there a better (faster, more convenient) way to concatenate multiple (nullable) objects?

I've ended up writing my own helper-class to concatenate objects: ConcatHelper.cs.
You see some examples in the gist, but also in the following snippet:
model.Summary = new ConcatHelper(", ")
.Concat(diploma.CodeProfession /* can be any object, will be null checked and ToString() called */)
.BraceStart() // if everything between the braces is null or empty, the braces will not appear
.Concat(diploma.CodeDiplomaType)
.Concat(label: DiplomaMessage.SrkRegisterId, labelSeparator: " ", valueDecorator: string.Empty, valueToAdd: diploma.SrkRegisterId)
.BraceEnd()
.Concat(diploma.CodeCountry)
.BraceStart()
.Concat(diploma.DateOfIssue?.Year.ToString(CultureInfo.InvariantCulture)) // no separator will be added if concatenated string is null or empty (no ", ,")
.BraceEnd()
.Concat(DiplomaMessage.Recognition, " ", string.Empty, diploma.DateOfRecognition?.Year.ToString(CultureInfo.InvariantCulture))
.ToString(); // results in something like: Drogist / Drogistin (Eidgenössischer Abschluss, SRK-Registrierungsnummer 3099-239), Irland (1991)
Benefits:
Does the null checks for you, avoids if/else branches.
Supports labeling, decorating and delimiting values. Doesn't add a label if the value will be null.
Joins everything, fluent notation - less codes
Good to do summaries of domain-objects.
Contra:
Rather slow:
I measured 7ms for the above example
I measured 0.01026ms per concatenation in a real-life example (see unit-test gist)
It's not static (could it be?)
Needs a list to keep track of everything.
Probably an overkill.
So as I am now starting to override a lot of ToString() methods of domain objects, I am unsure, if there is a better way.
By better I basically mean:
Is there a library that already does the stuff I need?
If not, can it be speed up without losing the convenient fluent-notation?
So I would be happy if you show me either a convenient way to achieve the same result without my helper, or helping me improving this class.
Greetings,
flo
Update:
Look at this gist for a real-life UnitTest.
I do not see any real problem with your code. But I would prefer a more streamlined syntax. It may look like this in the end:
string result = ConcatHelper.Concat(
diploma.CodeProfession,
new Brace(
diploma.CodeDiplomaType,
new LabeledItem(label: DiplomaMessage.SrkRegisterId, labelSeparator: " ",
valueDecorator: string.Empty, valueToAdd: diploma.SrkRegisterId)
),
diploma.CodeCountry,
new Brace(
diploma.DateOfIssue?.Year.ToString(CultureInfo.InvariantCulture)
),
DiplomaMessage.Recognition
).ToString();
no wall of Text
you do not have to repeat Concat over and over again
now chance to mix up the braces
Concat() would be of the type static ConcatHelper Concat(objs object[] params) in this case. Brace and LabeledItem need to be handled by ConcatHelper of course (if (obj is LabeledItem) { ... }).
Regarding your contras:
It should be fast enough (10us/ call should be okay). If you really need it faster, you probably should use a single String.Format()
Concat can be static. Just create the ConcatHelper-object inside the Concat-call.
Yes, it needs a list. Is there a problem?
It may be overkill, it may not. If you use this type of code regularly, Utility classes can save you much time and make the code more readable.
Variant 1 - stream like
var sb = new StringBuilder();
const string delimiter = ", ";
var first = true;
Action<object> append = _ => {
if(null!=_){
if(!first){ sb.Append(delimiter);}
first = false;
sb.Append(_.ToString());
}
}
append(diploma.X);
append(diploma.Y);
...
Another one - with collection
var data = new List<object>();
data.Add(diploma.X);
data.Add(diploma.Y);
...
var result = string.Join(", ",data.Where(_=>null!=_).Select(_=>_.ToString()));
It's not much efficient but it allow you addition step between data preparation and joining to do somwthing over collection itself.

How can i make this code more optimized - How can i replace the forloop.?

How can I improve the performance if this Code snippet.
bool OrSetFinalResult =true;
string OrSet = "(1&1)|0";
string[] AndSets = OrSet.Split('&');
foreach (string AndSet in AndSets)
{
if (AndSet == "0")
{
// A single "false" statement makes the entire And statement FALSE
OrSetFinalResult = false;
break;
}
}
Is there any way to remove the ForEach loop with any of the LINQ expressions ?
Sounds like:
if (AndSets.Contains("0"))
{
OrSetFinalResult = false;
}
No need for LINQ at all. It'll still loop internally of course, but it's still a lot simpler.
EDIT: As noted in comments, you could also use:
OrSetFinalResult = OrSetFinalResult && !OrSet.Split('&').Contains("0");
You don't include the definition of OrSetFinalResult so the fastest I can think of would be:
OrSetFinalResult = OrSetFinalResult && !OrSet.Split('&').Contains("0");
Since this skips the whole thing if it's already false anyway.
More generally, the best you can do with any search is:
If the collection is hashed based on the feature you are searching for (in this case, on the string itself) then O(1).
If the collection is sorted based on the feature you are searching for, then O(log n).
If the collection is not sorted, then O(n).
There are intermediate cases. E.g. if I want to find a particular X-Y coordinate from a set of coordinates only sorted on the X coordinate then it is O(√n log √n) assuming a reasonably even distribution.
In this case, we have the O(n) case.
Putting the values into a HashSet<string> would make this search O(1), but doing so is an O(n) operation in itself (and with higher constant effects). Therefore it would be a saving if you were going to search multiple times, but not if you were only going to search once.
You can use the Any operator in Linq.
string OrSet = "(1&1)|0";
string[] AndSets = OrSet.Split('&');
OrSetFinalResult = !AndSets.Any(x => x == "0");
Replacing string parsing with LINQ is the opposite of optimization in most cases (assuming you meant runtime optimization).
I'm guessing an linear tokenizer will be much much faster. Perhaps I'll do a sample benchmark (if I find time)
string OrSet = "(1&1)|0";
bool OrSetFinalResult = true;
if (OrSet.Contains("0"))
{
// A single "false" statement makes the entire And statement FALSE
OrSetFinalResult = false;
}
This will give you same result.
you can use the any operator in linq which would produce similar results.

Is string in array?

What would be the best way to look in a string[] to see if it contains a element. This was my first shot at it. But perhaps there is something that I am overlooking. The array size will be no larger than 200 elements.
bool isStringInArray(string[] strArray, string key)
{
for (int i = 0; i <= strArray.Length - 1; i++)
if (strArray[i] == key)
return true;
return false;
}
Just use the already built-in Contains() method:
using System.Linq;
//...
string[] array = { "foo", "bar" };
if (array.Contains("foo")) {
//...
}
I know this is old, but I wanted the new readers to know that there is a new method to do this using generics and extension methods.
You can read my blog post to see more information about how to do this, but the main idea is this:
By adding this extension method to your code:
public static bool IsIn<T>(this T source, params T[] values)
{
return values.Contains(source);
}
you can perform your search like this:
string myStr = "str3";
bool found = myStr.IsIn("str1", "str2", "str3", "str4");
It works on any type (as long as you create a good equals method). Any value type for sure.
You're simply after the Array.Exists function (or the Contains extension method if you're using .NET 3.5, which is slightly more convenient).
Linq (for s&g's):
var test = "This is the string I'm looking for";
var found = strArray.Any(x=>x == test);
or, depending on requirements
var found = strArray.Any(
x=>x.Equals(test, StringComparison.OrdinalIgnoreCase));
Is the array sorted? If so you could do a binary search. Here is the .NET implementation as well. If the array is sorted then a binary search will improve performance over any iterative solution.
Arrays are, in general, a poor data structure to use if you want to ask if a particular object is in the collection or not.
If you'll be running this search frequently, it might be worth it to use a Dictionary<string, something> rather than an array. Lookups in a Dictionary are O(1) (constant-time), while searching through the array is O(N) (takes time proportional to the length of the array).
Even if the array is only 200 items at most, if you do a lot of these searches, the Dictionary will likely be faster.
As mentioned many times in the thread above, it's dependent on the framework in use.
.Net Framework 3 and above has the .Contains() or Exists() methods for arrays. For other frameworks below, can do the following trick instead of looping through array...
((IList<string>)"Your String Array Here").Contains("Your Search String Here")
Not too sure on efficiency...
Dave
You can also use LINQ to iterate over the array. or you can use the Find method which takes a delegate to search for it. However I think the find method is a bit more expensive then just looping through.
This is quicker than iterating through the array manually:
static bool isStringInArray(string[] strArray, string key)
{
if (strArray.Contains(key))
return true;
return false;
}
If you don't want to or simply can't use Linq you can also use the static Array.Exists(...); function:
https://msdn.microsoft.com/en-us/library/yw84x8be%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
var arr = new string[]{"bird","foo","cat","dog"};
var catInside = Array.Exists(
arr, // your Array
(s)=>{ return s == "cat"; } // the Predicate
);
When the Predicate do return true once catInside will be true as well.

Categories