I have the following integer that I would like to check the value with an if statement.
int myInt = 3;
I tried this code which works, but I don't like having to write the variable name over and over.
if (myInt == 0 || myInt == 2 || myInt == 3 || myInt == 4)
{
Debug.WriteLine("Match");
}
else
{
Debug.WriteLine("No Match");
}
To demonstrate what I would like to ideally have, I tried something like this:
if (myInt == (0 | 2 | 3 | 4))
{
Debug.WriteLine("Match");
}
else
{
Debug.WriteLine("No Match");
}
But this doesn't work because the | is not quite the right operator because there is a type mismatch.
I then tried this, which also worked fine, but I still don't like having to declare an extra array.
if ((new int[] { 0, 2, 3, 4 }).Contains(myInt))
{
Debug.WriteLine("Match");
}
else
{
Debug.WriteLine("No Match");
}
The question is:
Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array or asking for the same variable name over and over with the || operator?
Your question is
Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array
but it really should be
Is there an operator that can satisfy what I'm trying to accomplish without declaring an additional array every time
There is nothing wrong with having that array once (and initializing it once), but there is a lot wrong with allocating it (and by extension GCing it later) every single time. So You need to declare an array once, something like
private static int matchArray[] = new int[] { 0, 2, 3, 4 };
and later just
if (matchArray.Contains(myInt)) ...
EDIT
If your match array is small, by any means use the answer by #JohnField and not this one - I stand corrected!
There is possibly a way to achieve what you want to do. They are called enum flags. Here there is a nice answer that explains how they work.
They way you want to use integers remind me of an enum where you have possibly multiple choices. Let's take the following case for instance:
[Flags]
enum DaysOfTheWeek
{
Sunday = 1,
Monday = 2,
Tuesday = 4,
Wednesday = 8,
Thursday = 16,
Friday = 32,
Saturday = 64
}
you can declare a variable as follow:
DaysOfTheWeek daysOfTheWeek;
daysOfTheWeek = DaysOfTheWeek.Monday | DaysOfTheWeek.Wednesday | DaysOfTheWeek.Friday;
and then check if your enum contains one of the values assigned above:
if((daysOfTheWeek & DaysOfTheWeek.Monday) == DaysOfTheWeek.Monday)
{
// Contains Monday!
}
else
{
// DOES NOT Contain Monday!
}
or from .NET 4 onwards:
if(daysOfTheWeek.HasFlag(DaysOfTheWeek.Monday))
{
...
}
Clearly this method is more elegant as long as you need to check for a small number of cases. If you have big array to check against, it would not be a suitable approach.
See, I'm just thinking... why not use a switch?
https://msdn.microsoft.com/en-us/library/06tc147t.aspx
int myInt = 3;
switch (myInt)
{
case 0:
case 2:
case 3:
case 4:
// Match
break;
default:
// No match
break;
}
If your array is in order, Array.BinarySearch will be more efficient than Contains, especially if the array has more than a few elements.
if (Array.BinarySearch(checkArray, myInt) >= 0)
;//match
else
;//no match
Usually, however, the best choice for the Contains operation is the HashSet. Thanks to JohanLarsson for pointing that out.
You could use a switch-case, but it could be argued that this looks messy.
switch (myInt)
{
case 0: //Add a comment to make it clear that
case 2: //this is a deliberate fall-through and
case 3: //not a mistake. (E.g. "//Deliberate
case 4: //fall-through for 0, 2, 3, 4")
//Insert code here in this section to do something
Debug.WriteLine("Match");
break; //Break statement is required to indicate end of section
default:
//The default section runs like an "else" statement
//It is optional and will run if none of the above
//cases are applicable.
Debug.WriteLine("No Match");
break;
} //end switch-case
I have trouble implementing the Y/N or y/n in the loop. I've designed it in a way that a user can use both the capital and small letters of the Y and N for their answer in a loop. by the way here's my code but can't seem to make it work:
do
{
Console.WriteLine("\nSelect additional topping/s\n");
Console.WriteLine("1 - Extra meat: 200");
Console.WriteLine("2 - Extra cheese: 100");
Console.WriteLine("3 - Extra veggies: 80\n");
int selectedTopping = Convert.ToInt32(Console.ReadLine());
switch (selectedTopping)
{
case 1:
pizza = new MeatToppings(pizza);
break;
case 2:
pizza = new CheeseToppings(pizza);
break;
case 3:
pizza = new VeggieToppings(pizza);
break;
default:
break;
}
Console.WriteLine("\nAdd more toppings? Y/N");
}
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));
while ((Console.ReadLine() == "Y") || (Console.ReadLine() == "y"));
This is going to read 2 different lines since you're calling ReadLine() twice. You need to call it once and save the value.
You can use ToUpper
while ((Console.ReadLine().ToUpper() == "Y") );
Try to use String.Equals and StringComparison:
String.Equals(Console.ReadLine(), "y", StringComparison.CurrentCultureIgnoreCase);
from MSDN:
CurrentCultureIgnoreCase: Compare strings using culture-sensitive sort rules, the current culture, and ignoring the case of the strings being compared.
OrdinalIgnoreCase: Compare strings using ordinal sort rules and ignoring the case of the strings being compared.
To check Y or y ignoring case, you should use string.Equals(string,StringComparison) overload.
while (Console.ReadLine().Equals("Y", StringComparison.InvariantCultureIgnoreCase));
Please see the The Turkish İ Problem and Why You Should Care before using ToUpper or ToLower for string comparison with ignore case.
Your current code is reading the lines from console twice, that is why your code is holding up for the 2nd value.
As Austin just pointed out, you are using ReadLine twice in the while loop statement.
One thing worth mentioning is try to follow the rule of modularity, it will help speed up implementing and debugging our code.
It's been a while since I did any C# programming so sudo-coding this in Java style.
Since it's a command line programming you are probably have to validate user input more than once. One thing I would do is make a utility class to contains common user input tasks.
public class TerminalUtil {
private TerminalUtil() {}
public static boolean isYes(String msg){ return (msg.ToUpper() == "Y" || msg.ToUpper() == "YES"); }
public static boolean isNo(String msg){ return (msg.ToUpper() == "N" || msg.ToUpper() == "NO"); }
// You also might want basic conditionals to check if string is numeric or contains letters.
// I like using recursion for command line utilities so having a method that can re-print messages is handy
public static void display(String[] messages){
for(String msg : messages){
Console.WriteLine(msg);
}
}
public static boolean enterYesOrNo(String[] messages, String[] errorMessages){
display(messages)
String input = Console.ReadLine();
if( isYes(input) ){
return true;
} else if( isNo(input) ){
return false;
} else {
display(errorMessages); // Maybe something like, you didn't enter a yes or no value.
enterYesOrNo(messages, errorMessages); // Recursive loop to try again.
}
}
}
Here is what the code to order a pizza might look like
public class OrderPizza{
public static int selectToppings(){
String[] message = new String[4];
message[0] = ("\nSelect additional topping/s\n");
message[1] = ("1 - Extra meat: 200");
message[2] = ("2 - Extra cheese: 100");
message[3] = ("3 - Extra veggies: 80\n");
int option = TerminalUtils.entryNumeric(message, {"You entered an non-numeric character, try again"} );
if( option > 0 && option <= 3 ){
return option;
} else {
Console.WriteLine("Number must be between 1 - 3, try again.");
return selectToppings();
}
}
public static Pizza order(){
Pizza pizza = new Pizza();
while(true){
int toppingCode = selectTopping();
pizza.addTopping(toppingCode);
if(!TerminalUtil.enterYesOrNo({"\nAdd more toppings? Y/N"}, {"Please enter a 'Y'es or 'N'o"}) ){
break;
}
}
}
}
The main benefit of this is that the business logic of the while loop has been reduced and you can reuse the code in TerminalUtils. Also this is by no mean a elegant solution, I'm lazy and it's 3am IRL, but it's should be enough to the ball rolling.
One thing you should probably reconsider doing is using integer codes to represent toppings. Using an enum might make things easier to implement.
I also notice that you add three different types of pizza's, which I'm assuming three separate objects.
Since you are looping to add toppings to a pizza, make an abstract class of pizza. This way you could extend it generic pre-built pizzas such as pepperoni or cheese and use the abstract pizza class if you want the customer to customize their order.
I didn't found better way than:
while ( str!="N" )
{
str = Console.ReadLine();
str = str.ToUpper();
if (str == "Y");
break;
};
I'm trying to do some parsing that will be easier using regular expressions.
The input is an array (or enumeration) of bytes.
I don't want to convert the bytes to chars for the following reasons:
Computation efficiency
Memory consumption efficiency
Some non-printable bytes might be complex to convert to chars. Not all the bytes are printable.
So I can't use Regex.
The only solution I know, is using Boost.Regex (which works on bytes - C chars), but this is a C++ library that wrapping using C++/CLI will take considerable work.
How can I use regular expressions on bytes in .NET directly, without working with .NET strings and chars?
Thank you.
There is a bit of impedance mismatch going on here. You want to work with Regular expressions in .Net which use strings (multi-byte characters), but you want to work with single byte characters. You can't have both at the same time using .Net as per usual.
However, to break this mismatch down, you could deal with a string in a byte oriented fashion and mutate it. The mutated string can then act as a re-usable buffer. In this way you will not have to convert bytes to chars, or convert your input buffer to a string (as per your question).
An example:
//BLING
byte[] inputBuffer = { 66, 76, 73, 78, 71 };
string stringBuffer = new string('\0', 1000);
Regex regex = new Regex("ING", RegexOptions.Compiled);
unsafe
{
fixed (char* charArray = stringBuffer)
{
byte* buffer = (byte*)(charArray);
//Hard-coded example of string mutation, in practice you would
//loop over your input buffers and regex\match so that the string
//buffer is re-used.
buffer[0] = inputBuffer[0];
buffer[2] = inputBuffer[1];
buffer[4] = inputBuffer[2];
buffer[6] = inputBuffer[3];
buffer[8] = inputBuffer[4];
Console.WriteLine("Mutated string:'{0}'.",
stringBuffer.Substring(0, inputBuffer.Length));
Match match = regex.Match(stringBuffer, 0, inputBuffer.Length);
Console.WriteLine("Position:{0} Length:{1}.", match.Index, match.Length);
}
}
Using this technique you can allocate a string "buffer" which can be re-used as the input to Regex, but you can mutate it with your bytes each time. This avoids the overhead of converting\encoding your byte array into a new .Net string each time you want to do a match. This could prove to be very significant as I have seen many an algorithm in .Net try to go at a million miles an hour only to be brought to its knees by string generation and the subsequent heap spamming and time spent in GC.
Obviously this is unsafe code, but it is .Net.
The results of the Regex will generate strings though, so you have an issue here. I'm not sure if there is a way of using Regex that will not generate new strings. You can certainly get at the match index and length information but the string generation violates your requirements for memory efficiency.
Update
Actually after disassembling Regex\Match\Group\Capture, it looks like it only generates the captured string when you access the Value property, so you may at least not be generating strings if you only access index and length properties. However, you will be generating all the supporting Regex objects.
Well, if I faced this problem, I would DO the C++/CLI wrapper, except I'd create specialized code for what I want to achieve. Eventually develop the wrapper with time to do general things, but this just an option.
The first step is to wrap the Boost::Regex input and output only. Create specialized functions in C++ that do all the stuff you want and use CLI just to pass the input data to the C++ code and then fetch the result back with the CLI. This doesn't look to me like too much work to do.
Update:
Let me try to clarify my point. Even though I may be wrong, I believe you wont be able to find any .NET Binary Regex implementation that you could use. That is why - whether you like it or not - you will be forced to choose between CLI wrapper and bytes-to-chars conversion to use .NET's Regex. In my opinion the wrapper is better choice, because it will be working faster. I did not do any benchmarking, this is just an assumption based on:
Using wrapper you just have to cast
the pointer type (bytes <-> chars).
Using .NET's Regex you have to
convert each byte of the input.
As an alternative to using unsafe, just consider writing a simple, recursive comparer like:
static bool Evaluate(byte[] data, byte[] sequence, int dataIndex=0, int sequenceIndex=0)
{
if (sequence[sequenceIndex] == data[dataIndex])
{
if (sequenceIndex == sequence.Length - 1)
return true;
else if (dataIndex == data.Length - 1)
return false;
else
return Evaluate(data, sequence, dataIndex + 1, sequenceIndex + 1);
}
else
{
if (dataIndex < data.Length - 1)
return Evaluate(data, sequence, dataIndex+1, 0);
else
return false;
}
}
You could improve efficiency in a number of ways (i.e. seeking the first byte match instead of iterating, etc.) but this could get you started... hope it helps.
I personally went a different approach and wrote a small state machine that can be extended. I believe if parsing protocol data this is much more readable than regex.
bool ParseUDSResponse(PassThruMsg rxMsg, UDScmd.Mode txMode, byte txSubFunction, out UDScmd.Response functionResponse, out byte[] payload)
{
payload = new byte[0];
functionResponse = UDScmd.Response.UNKNOWN;
bool positiveReponse = false;
var rxMsgBytes = rxMsg.GetBytes();
//Iterate the reply bytes to find the echod ECU index, response code, function response and payload data if there is any
//If we could use some kind of HEX regex this would be a bit neater
//Iterate until we get past any and all null padding
int stateMachine = 0;
for (int i = 0; i < rxMsgBytes.Length; i++)
{
switch (stateMachine)
{
case 0:
if (rxMsgBytes[i] == 0x07) stateMachine = 1;
break;
case 1:
if (rxMsgBytes[i] == 0xE8) stateMachine = 2;
else return false;
case 2:
if (rxMsgBytes[i] == (byte)txMode + (byte)OBDcmd.Reponse.SUCCESS)
{
//Positive response to the requested mode
positiveReponse = true;
}
else if(rxMsgBytes[i] != (byte)OBDcmd.Reponse.NEGATIVE_RESPONSE)
{
//This is an invalid response, give up now
return false;
}
stateMachine = 3;
break;
case 3:
functionResponse = (UDScmd.Response)rxMsgBytes[i];
if (positiveReponse && rxMsgBytes[i] == txSubFunction)
{
//We have a positive response and a positive subfunction code (subfunction is reflected)
int payloadLength = rxMsgBytes.Length - i;
if(payloadLength > 0)
{
payload = new byte[payloadLength];
Array.Copy(rxMsgBytes, i, payload, 0, payloadLength);
}
return true;
} else
{
//We had a positive response but a negative subfunction error
//we return the function error code so it can be relayed
return false;
}
default:
return false;
}
}
return false;
}
How to write following statement in c using switch statement in c
int i = 10;
int j = 20;
if (i == 10 && j == 20)
{
Mymethod();
}
else if (i == 100 && j == 200)
{
Yourmethod();
}
else if (i == 1000 || j == 2000) // OR
{
Anymethod();
}
EDIT:
I have changed the last case from 'and' to 'or' later. So I appologise from people who answered my question before this edit.
This scenario is for example, I just wanted to know that is it possible or not. I have google this and found it is not possible but I trust gurus on stackoverflow more.
Thanks
You're pressing for answers that will unnaturally force this code into a switch - that's not the right approach in C, C++ or C# for the problem you've described. Live with the if statements, as using a switch in this instance leads to less readable code and the possibility that a slip-up will introduce a bug.
There are languages that will evaluate a switch statement syntax similar to a sequence of if statements, but C, C++, and C# aren't among them.
After Jon Skeet's comment that it can be "interesting to try to make it work", I'm going to go against my initial judgment and play along because it's certainly true that one can learn by trying alternatives to see where they work and where they don't work. Hopefully I won't end up muddling things more than I should...
The targets for a switch statement in the languages under consideration need to be constants - they aren't expressions that are evaluated at runtime. However, you can potentially get a behavior similar to what you're looking for if you can map the conditions that you want to have as switch targets to a hash function that will produce a perfect hash the matches up to the conditions. If that can be done, you can call the hash function and switch on the value it produces.
The C# compiler does something similar to this automatically for you when you want to switch on a string value. In C, I've manually done something similar when I want to switch on a string. I place the target strings in a table along with enumerations that are used to identify the strings, and I switch on the enum:
char* cmdString = "copystuff"; // a string with a command identifier,
// maybe obtained from console input
StrLookupValueStruct CmdStringTable[] = {
{ "liststuff", CMD_LIST },
{ "docalcs", CMD_CALC },
{ "copystuff", CMD_COPY },
{ "delete", CMD_DELETE },
{ NULL, CMD_UNKNOWN },
};
int cmdId = strLookupValue( cmdString, CmdStringTable); // transform the string
// into an enum
switch (cmdId) {
case CMD_LIST:
doList();
break;
case CMD_CALC:
doCalc();
break;
case CMD_COPY:
doCopy();
break;
// etc...
}
Instead of having to use a sequence of if statements:
if (strcmp( cmdString, "liststuff") == 0) {
doList();
}
else if (strcmp( cmdString, "docalcs") == 0) {
doCalc();
}
else if (strcmp( cmdString, "copystuff") == 0) {
doCopy();
}
// etc....
As an aside, for the string to function mapping here I personally find the table lookup/switch statement combination to be a bit more readable, but I imagine there are people who might prefer the more direct approach of the if sequence.
The set of expressions you have in your question don't look particularly simple to transform into a hash - your hash function would almost certainly end up being a sequence of if statements - you would have basically just moved the construct somewhere else. Jon Skeet's original answer was essentially to turn your expressions into a hash, but when the or operation got thrown into the mix of one of the tests, the hash function broke down.
In general you can't. What you are doing already is fine, although you might want to add an else clause at the end to catch unexpected inputs.
In your specific example it seems that j is often twice the value of i. If that is a general rule you could try to take advantage of that by doing something like this instead:
if (i * 2 == j) /* Watch out for overflow here if i could be large! */
{
switch (i)
{
case 10:
// ...
break;
case 100:
// ...
break;
// ...
}
}
(Removed original answer: I'd missed the fact that the condition was an "OR" rather than an "AND". EDIT: Ah, because apparently it wasn't to start with.)
You could still theoretically use something like my original code (combining two 32-bit integers into one 64-bit integer and switching on that), although there would be 2^33 case statements covering the last condition. I doubt that any compiler would actually make it through such code :)
But basically, no: use the if/else structure instead.
Lets say I have the option of identifying a code path to take on the basis of a string comparison or else iffing the type:
Which is quicker and why?
switch(childNode.Name)
{
case "Bob":
break;
case "Jill":
break;
case "Marko":
break;
}
if(childNode is Bob)
{
}
elseif(childNode is Jill)
{
}
else if(childNode is Marko)
{
}
Update: The main reason I ask this is because the switch statement is perculiar about what counts as a case. For example it wont allow you to use variables, only constants which get moved to the main assembly. I assumed it had this restriction due to some funky stuff it was doing. If it is only translating to elseifs (as one poster commented) then why are we not allowed variables in case statements?
Caveat: I am post-optimising. This method is called many times in a slow part of the app.
Greg's profile results are great for the exact scenario he covered, but interestingly, the relative costs of the different methods change dramatically when considering a number of different factors including the number of types being compared, and the relative frequency and any patterns in the underlying data.
The simple answer is that nobody can tell you what the performance difference is going to be in your specific scenario, you will need to measure the performance in different ways yourself in your own system to get an accurate answer.
The If/Else chain is an effective approach for a small number of type comparisons, or if you can reliably predict which few types are going to make up the majority of the ones that you see. The potential problem with the approach is that as the number of types increases, the number of comparisons that must be executed increases as well.
if I execute the following:
int value = 25124;
if(value == 0) ...
else if (value == 1) ...
else if (value == 2) ...
...
else if (value == 25124) ...
each of the previous if conditions must be evaluated before the correct block is entered. On the other hand
switch(value) {
case 0:...break;
case 1:...break;
case 2:...break;
...
case 25124:...break;
}
will perform one simple jump to the correct bit of code.
Where it gets more complicated in your example is that your other method uses a switch on strings rather than integers which gets a little more complicated. At a low level, strings can't be switched on in the same way that integer values can so the C# compiler does some magic to make this work for you.
If the switch statement is "small enough" (where the compiler does what it thinks is best automatically) switching on strings generates code that is the same as an if/else chain.
switch(someString) {
case "Foo": DoFoo(); break;
case "Bar": DoBar(); break;
default: DoOther; break;
}
is the same as:
if(someString == "Foo") {
DoFoo();
} else if(someString == "Bar") {
DoBar();
} else {
DoOther();
}
Once the list of items in the dictionary gets "big enough" the compiler will automatically create an internal dictionary that maps from the strings in the switch to an integer index and then a switch based on that index.
It looks something like this (Just imagine more entries than I am going to bother to type)
A static field is defined in a "hidden" location that is associated with the class containing the switch statement of type Dictionary<string, int> and given a mangled name
//Make sure the dictionary is loaded
if(theDictionary == null) {
//This is simplified for clarity, the actual implementation is more complex
// in order to ensure thread safety
theDictionary = new Dictionary<string,int>();
theDictionary["Foo"] = 0;
theDictionary["Bar"] = 1;
}
int switchIndex;
if(theDictionary.TryGetValue(someString, out switchIndex)) {
switch(switchIndex) {
case 0: DoFoo(); break;
case 1: DoBar(); break;
}
} else {
DoOther();
}
In some quick tests that I just ran, the If/Else method is about 3x as fast as the switch for 3 different types (where the types are randomly distributed). At 25 types the switch is faster by a small margin (16%) at 50 types the switch is more than twice as fast.
If you are going to be switching on a large number of types, I would suggest a 3rd method:
private delegate void NodeHandler(ChildNode node);
static Dictionary<RuntimeTypeHandle, NodeHandler> TypeHandleSwitcher = CreateSwitcher();
private static Dictionary<RuntimeTypeHandle, NodeHandler> CreateSwitcher()
{
var ret = new Dictionary<RuntimeTypeHandle, NodeHandler>();
ret[typeof(Bob).TypeHandle] = HandleBob;
ret[typeof(Jill).TypeHandle] = HandleJill;
ret[typeof(Marko).TypeHandle] = HandleMarko;
return ret;
}
void HandleChildNode(ChildNode node)
{
NodeHandler handler;
if (TaskHandleSwitcher.TryGetValue(Type.GetRuntimeType(node), out handler))
{
handler(node);
}
else
{
//Unexpected type...
}
}
This is similar to what Ted Elliot suggested, but the usage of runtime type handles instead of full type objects avoids the overhead of loading the type object through reflection.
Here are some quick timings on my machine:
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 5 types
Method Time % of optimal
If/Else 179.67 100.00
TypeHandleDictionary 321.33 178.85
TypeDictionary 377.67 210.20
Switch 492.67 274.21
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 10 types
Method Time % of optimal
If/Else 271.33 100.00
TypeHandleDictionary 312.00 114.99
TypeDictionary 374.33 137.96
Switch 490.33 180.71
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 15 types
Method Time % of optimal
TypeHandleDictionary 312.00 100.00
If/Else 369.00 118.27
TypeDictionary 371.67 119.12
Switch 491.67 157.59
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 20 types
Method Time % of optimal
TypeHandleDictionary 335.33 100.00
TypeDictionary 373.00 111.23
If/Else 462.67 137.97
Switch 490.33 146.22
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 25 types
Method Time % of optimal
TypeHandleDictionary 319.33 100.00
TypeDictionary 371.00 116.18
Switch 483.00 151.25
If/Else 562.00 175.99
Testing 3 iterations with 5,000,000 data elements (mode=Random) and 50 types
Method Time % of optimal
TypeHandleDictionary 319.67 100.00
TypeDictionary 376.67 117.83
Switch 453.33 141.81
If/Else 1,032.67 323.04
On my machine at least, the type handle dictionary approach beats all of the others for anything over 15 different types when the distribution
of the types used as input to the method is random.
If on the other hand, the input is composed entirely of the type that is checked first in the if/else chain that method is much faster:
Testing 3 iterations with 5,000,000 data elements (mode=UniformFirst) and 50 types
Method Time % of optimal
If/Else 39.00 100.00
TypeHandleDictionary 317.33 813.68
TypeDictionary 396.00 1,015.38
Switch 403.00 1,033.33
Conversely, if the input is always the last thing in the if/else chain, it has the opposite effect:
Testing 3 iterations with 5,000,000 data elements (mode=UniformLast) and 50 types
Method Time % of optimal
TypeHandleDictionary 317.67 100.00
Switch 354.33 111.54
TypeDictionary 377.67 118.89
If/Else 1,907.67 600.52
If you can make some assumptions about your input, you might get the best performance from a hybrid approach where you perform if/else checks for the few types that are most common, and then fall back to a dictionary-driven approach if those fail.
Firstly, you're comparing apples and oranges. You'd first need to compare switch on type vs switch on string, and then if on type vs if on string, and then compare the winners.
Secondly, this is the kind of thing OO was designed for. In languages that support OO, switching on type (of any kind) is a code smell that points to poor design. The solution is to derive from a common base with an abstract or virtual method (or a similar construct, depending on your language)
eg.
class Node
{
public virtual void Action()
{
// Perform default action
}
}
class Bob : Node
{
public override void Action()
{
// Perform action for Bill
}
}
class Jill : Node
{
public override void Action()
{
// Perform action for Jill
}
}
Then, instead of doing the switch statement, you just call childNode.Action()
I just implemented a quick test application and profiled it with ANTS 4.
Spec: .Net 3.5 sp1 in 32bit Windows XP, code built in release mode.
3 million tests:
Switch: 1.842 seconds
If: 0.344 seconds.
Furthermore, the switch statement results reveal (unsurprisingly) that longer names take longer.
1 million tests
Bob: 0.612 seconds.
Jill: 0.835 seconds.
Marko: 1.093 seconds.
I looks like the "If Else" is faster, at least the the scenario I created.
class Program
{
static void Main( string[] args )
{
Bob bob = new Bob();
Jill jill = new Jill();
Marko marko = new Marko();
for( int i = 0; i < 1000000; i++ )
{
Test( bob );
Test( jill );
Test( marko );
}
}
public static void Test( ChildNode childNode )
{
TestSwitch( childNode );
TestIfElse( childNode );
}
private static void TestIfElse( ChildNode childNode )
{
if( childNode is Bob ){}
else if( childNode is Jill ){}
else if( childNode is Marko ){}
}
private static void TestSwitch( ChildNode childNode )
{
switch( childNode.Name )
{
case "Bob":
break;
case "Jill":
break;
case "Marko":
break;
}
}
}
class ChildNode { public string Name { get; set; } }
class Bob : ChildNode { public Bob(){ this.Name = "Bob"; }}
class Jill : ChildNode{public Jill(){this.Name = "Jill";}}
class Marko : ChildNode{public Marko(){this.Name = "Marko";}}
Switch statement is faster to execute than the if-else-if ladder. This is due to the compiler's ability to optimise the switch statement. In the case of the if-else-if ladder, the code must process each if statement in the order determined by the programmer. However, because each case within a switch statement does not rely on earlier cases, the compiler is able to re-order the testing in such a way as to provide the fastest execution.
If you've got the classes made, I'd suggest using a Strategy design pattern instead of switch or elseif.
Try using enumerations for each object, you can switch on enums quickly and easily.
Unless you've already written this and find you have a performance problem I wouldn't worry about which is quicker. Go with the one that's more readable. Remember, "Premature optimization is the root of all evil." - Donald Knuth
A SWITCH construct was originally intended for integer data; it's intent was to use the argument directly as a index into a "dispatch table", a table of pointers. As such, there would be a single test, then launch directly to the relevant code, rather than a series of tests.
The difficulty here is that it's use has been generalized to "string" types, which obviously cannot be used as an index, and all advantage of the SWITCH construct is lost.
If speed is your intended goal, the problem is NOT your code, but your data structure. If the "name" space is as simple as you show it, better to code it into an integer value (when data is created, for example), and use this integer in the "many times in a slow part of the app".
If the types you're switching on are primitive .NET types you can use Type.GetTypeCode(Type), but if they're custom types they will all come back as TypeCode.Object.
A dictionary with delegates or handler classes might work as well.
Dictionary<Type, HandlerDelegate> handlers = new Dictionary<Type, HandlerDelegate>();
handlers[typeof(Bob)] = this.HandleBob;
handlers[typeof(Jill)] = this.HandleJill;
handlers[typeof(Marko)] = this.HandleMarko;
handlers[childNode.GetType()](childNode);
/// ...
private void HandleBob(Node childNode) {
// code to handle Bob
}
The switch() will compile out to code equivalent to a set of else ifs. The string comparisons will be much slower than the type comparisons.
I recall reading in several reference books that the if/else branching is quicker than the switch statement. However, a bit of research on Blackwasp shows that the switch statement is actually faster:
http://www.blackwasp.co.uk/SpeedTestIfElseSwitch.aspx
In reality, if you're comparing the typical 3 to 10 (or so) statements, I seriously doubt there's any real performance gain using one or the other.
As Chris has already said, go for readability:
What is quicker, switch on string or elseif on type?
I think the main performance issue here is, that in the switch block, you compare strings, and that in the if-else block, you check for types... Those two are not the same, and therefore, I'd say you're "comparing potatoes to bananas".
I'd start by comparing this:
switch(childNode.Name)
{
case "Bob":
break;
case "Jill":
break;
case "Marko":
break;
}
if(childNode.Name == "Bob")
{}
else if(childNode.Name == "Jill")
{}
else if(childNode.Name == "Marko")
{}
I'm not sure how faster it could be the right design would be to go for polymorphism.
interface INode
{
void Action;
}
class Bob : INode
{
public void Action
{
}
}
class Jill : INode
{
public void Action
{
}
}
class Marko : INode
{
public void Action
{
}
}
//Your function:
void Do(INode childNode)
{
childNode.Action();
}
Seeing what your switch statement does will help better. If your function is not really anything about an action on the type, may be you could define an enum on each type.
enum NodeType { Bob, Jill, Marko, Default }
interface INode
{
NodeType Node { get; };
}
class Bob : INode
{
public NodeType Node { get { return NodeType.Bob; } }
}
class Jill : INode
{
public NodeType Node { get { return NodeType.Jill; } }
}
class Marko : INode
{
public NodeType Node { get { return NodeType.Marko; } }
}
//Your function:
void Do(INode childNode)
{
switch(childNode.Node)
{
case Bob:
break;
case Jill:
break;
case Marko:
break;
Default:
throw new ArgumentException();
}
}
I assume this has to be faster than both approaches in question. You might want to try abstract class route if nanoseconds does matter for you.
I created a little console to show my solution, just to highlight the speed difference. I used a different string hash algorithm as the certificate version is to slow for me on runtime and duplicates are unlikely and if so my switch statement would fail (never happened till now). My unique hash extension method is included in the code below.
I will take 29 ticks over 695 ticks any time, specially when using critical code.
With a set of strings from a given database you can create a small application to create the constant in a given file for you to use in your code, if values are added you just re-run your batch and constants are generated and picked up by the solution.
public static class StringExtention
{
public static long ToUniqueHash(this string text)
{
long value = 0;
var array = text.ToCharArray();
unchecked
{
for (int i = 0; i < array.Length; i++)
{
value = (value * 397) ^ array[i].GetHashCode();
value = (value * 397) ^ i;
}
return value;
}
}
}
public class AccountTypes
{
static void Main()
{
var sb = new StringBuilder();
sb.AppendLine($"const long ACCOUNT_TYPE = {"AccountType".ToUniqueHash()};");
sb.AppendLine($"const long NET_LIQUIDATION = {"NetLiquidation".ToUniqueHash()};");
sb.AppendLine($"const long TOTAL_CASH_VALUE = {"TotalCashValue".ToUniqueHash()};");
sb.AppendLine($"const long SETTLED_CASH = {"SettledCash".ToUniqueHash()};");
sb.AppendLine($"const long ACCRUED_CASH = {"AccruedCash".ToUniqueHash()};");
sb.AppendLine($"const long BUYING_POWER = {"BuyingPower".ToUniqueHash()};");
sb.AppendLine($"const long EQUITY_WITH_LOAN_VALUE = {"EquityWithLoanValue".ToUniqueHash()};");
sb.AppendLine($"const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = {"PreviousEquityWithLoanValue".ToUniqueHash()};");
sb.AppendLine($"const long GROSS_POSITION_VALUE ={ "GrossPositionValue".ToUniqueHash()};");
sb.AppendLine($"const long REQT_EQUITY = {"ReqTEquity".ToUniqueHash()};");
sb.AppendLine($"const long REQT_MARGIN = {"ReqTMargin".ToUniqueHash()};");
sb.AppendLine($"const long SPECIAL_MEMORANDUM_ACCOUNT = {"SMA".ToUniqueHash()};");
sb.AppendLine($"const long INIT_MARGIN_REQ = { "InitMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long MAINT_MARGIN_REQ = {"MaintMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long AVAILABLE_FUNDS = {"AvailableFunds".ToUniqueHash()};");
sb.AppendLine($"const long EXCESS_LIQUIDITY = {"ExcessLiquidity".ToUniqueHash()};");
sb.AppendLine($"const long CUSHION = {"Cushion".ToUniqueHash()};");
sb.AppendLine($"const long FULL_INIT_MARGIN_REQ = {"FullInitMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long FULL_MAINTMARGIN_REQ ={ "FullMaintMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long FULL_AVAILABLE_FUNDS = {"FullAvailableFunds".ToUniqueHash()};");
sb.AppendLine($"const long FULL_EXCESS_LIQUIDITY ={ "FullExcessLiquidity".ToUniqueHash()};");
sb.AppendLine($"const long LOOK_AHEAD_INIT_MARGIN_REQ = {"LookAheadInitMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long LOOK_AHEAD_MAINT_MARGIN_REQ = {"LookAheadMaintMarginReq".ToUniqueHash()};");
sb.AppendLine($"const long LOOK_AHEAD_AVAILABLE_FUNDS = {"LookAheadAvailableFunds".ToUniqueHash()};");
sb.AppendLine($"const long LOOK_AHEAD_EXCESS_LIQUIDITY = {"LookAheadExcessLiquidity".ToUniqueHash()};");
sb.AppendLine($"const long HIGHEST_SEVERITY = {"HighestSeverity".ToUniqueHash()};");
sb.AppendLine($"const long DAY_TRADES_REMAINING = {"DayTradesRemaining".ToUniqueHash()};");
sb.AppendLine($"const long LEVERAGE = {"Leverage".ToUniqueHash()};");
Console.WriteLine(sb.ToString());
Test();
}
public static void Test()
{
//generated constant values
const long ACCOUNT_TYPE = -3012481629590703298;
const long NET_LIQUIDATION = 5886477638280951639;
const long TOTAL_CASH_VALUE = 2715174589598334721;
const long SETTLED_CASH = 9013818865418133625;
const long ACCRUED_CASH = -1095823472425902515;
const long BUYING_POWER = -4447052054809609098;
const long EQUITY_WITH_LOAN_VALUE = -4088154623329785565;
const long PREVIOUS_EQUITY_WITH_LOAN_VALUE = 6224054330592996694;
const long GROSS_POSITION_VALUE = -7316842993788269735;
const long REQT_EQUITY = -7457439202928979430;
const long REQT_MARGIN = -7525806483981945115;
const long SPECIAL_MEMORANDUM_ACCOUNT = -1696406879233404584;
const long INIT_MARGIN_REQ = 4495254338330797326;
const long MAINT_MARGIN_REQ = 3923858659879350034;
const long AVAILABLE_FUNDS = 2736927433442081110;
const long EXCESS_LIQUIDITY = 5975045739561521360;
const long CUSHION = 5079153439662500166;
const long FULL_INIT_MARGIN_REQ = -6446443340724968443;
const long FULL_MAINTMARGIN_REQ = -8084126626285123011;
const long FULL_AVAILABLE_FUNDS = 1594040062751632873;
const long FULL_EXCESS_LIQUIDITY = -2360941491690082189;
const long LOOK_AHEAD_INIT_MARGIN_REQ = 5230305572167766821;
const long LOOK_AHEAD_MAINT_MARGIN_REQ = 4895875570930256738;
const long LOOK_AHEAD_AVAILABLE_FUNDS = -7687608210548571554;
const long LOOK_AHEAD_EXCESS_LIQUIDITY = -4299898188451362207;
const long HIGHEST_SEVERITY = 5831097798646393988;
const long DAY_TRADES_REMAINING = 3899479916235857560;
const long LEVERAGE = 1018053116254258495;
bool found = false;
var sValues = new string[] {
"AccountType"
,"NetLiquidation"
,"TotalCashValue"
,"SettledCash"
,"AccruedCash"
,"BuyingPower"
,"EquityWithLoanValue"
,"PreviousEquityWithLoanValue"
,"GrossPositionValue"
,"ReqTEquity"
,"ReqTMargin"
,"SMA"
,"InitMarginReq"
,"MaintMarginReq"
,"AvailableFunds"
,"ExcessLiquidity"
,"Cushion"
,"FullInitMarginReq"
,"FullMaintMarginReq"
,"FullAvailableFunds"
,"FullExcessLiquidity"
,"LookAheadInitMarginReq"
,"LookAheadMaintMarginReq"
,"LookAheadAvailableFunds"
,"LookAheadExcessLiquidity"
,"HighestSeverity"
,"DayTradesRemaining"
,"Leverage"
};
long t1, t2;
var sw = System.Diagnostics.Stopwatch.StartNew();
foreach (var name in sValues)
{
switch (name)
{
case "AccountType": found = true; break;
case "NetLiquidation": found = true; break;
case "TotalCashValue": found = true; break;
case "SettledCash": found = true; break;
case "AccruedCash": found = true; break;
case "BuyingPower": found = true; break;
case "EquityWithLoanValue": found = true; break;
case "PreviousEquityWithLoanValue": found = true; break;
case "GrossPositionValue": found = true; break;
case "ReqTEquity": found = true; break;
case "ReqTMargin": found = true; break;
case "SMA": found = true; break;
case "InitMarginReq": found = true; break;
case "MaintMarginReq": found = true; break;
case "AvailableFunds": found = true; break;
case "ExcessLiquidity": found = true; break;
case "Cushion": found = true; break;
case "FullInitMarginReq": found = true; break;
case "FullMaintMarginReq": found = true; break;
case "FullAvailableFunds": found = true; break;
case "FullExcessLiquidity": found = true; break;
case "LookAheadInitMarginReq": found = true; break;
case "LookAheadMaintMarginReq": found = true; break;
case "LookAheadAvailableFunds": found = true; break;
case "LookAheadExcessLiquidity": found = true; break;
case "HighestSeverity": found = true; break;
case "DayTradesRemaining": found = true; break;
case "Leverage": found = true; break;
default: found = false; break;
}
if (!found)
throw new NotImplementedException();
}
t1 = sw.ElapsedTicks;
sw.Restart();
foreach (var name in sValues)
{
switch (name.ToUniqueHash())
{
case ACCOUNT_TYPE:
found = true;
break;
case NET_LIQUIDATION:
found = true;
break;
case TOTAL_CASH_VALUE:
found = true;
break;
case SETTLED_CASH:
found = true;
break;
case ACCRUED_CASH:
found = true;
break;
case BUYING_POWER:
found = true;
break;
case EQUITY_WITH_LOAN_VALUE:
found = true;
break;
case PREVIOUS_EQUITY_WITH_LOAN_VALUE:
found = true;
break;
case GROSS_POSITION_VALUE:
found = true;
break;
case REQT_EQUITY:
found = true;
break;
case REQT_MARGIN:
found = true;
break;
case SPECIAL_MEMORANDUM_ACCOUNT:
found = true;
break;
case INIT_MARGIN_REQ:
found = true;
break;
case MAINT_MARGIN_REQ:
found = true;
break;
case AVAILABLE_FUNDS:
found = true;
break;
case EXCESS_LIQUIDITY:
found = true;
break;
case CUSHION:
found = true;
break;
case FULL_INIT_MARGIN_REQ:
found = true;
break;
case FULL_MAINTMARGIN_REQ:
found = true;
break;
case FULL_AVAILABLE_FUNDS:
found = true;
break;
case FULL_EXCESS_LIQUIDITY:
found = true;
break;
case LOOK_AHEAD_INIT_MARGIN_REQ:
found = true;
break;
case LOOK_AHEAD_MAINT_MARGIN_REQ:
found = true;
break;
case LOOK_AHEAD_AVAILABLE_FUNDS:
found = true;
break;
case LOOK_AHEAD_EXCESS_LIQUIDITY:
found = true;
break;
case HIGHEST_SEVERITY:
found = true;
break;
case DAY_TRADES_REMAINING:
found = true;
break;
case LEVERAGE:
found = true;
break;
default:
found = false;
break;
}
if (!found)
throw new NotImplementedException();
}
t2 = sw.ElapsedTicks;
sw.Stop();
Console.WriteLine($"String switch:{t1:N0} long switch:{t2:N0}");
var faster = (t1 > t2) ? "Slower" : "faster";
Console.WriteLine($"String switch: is {faster} than long switch: by {Math.Abs(t1-t2)} Ticks");
Console.ReadLine();
}
well it depend on language you need to test yourself to see timing that which one is fast. like in php web language if / else if is fast compare to switch so you need to find it out by running some bench basic code in your desire language.
personally i prefer if / else if for code reading as switch statements can be nightmare to read where there is big code blocks in each condition as you will have to look for break keywords it each end point manually while with if / else if due to the start and end braces its easy to trace code blocks.
php
String comparison will always rely completely on the runtime environment (unless the strings are statically allocated, though the need to compare those to each other is debatable). Type comparison, however, can be done through dynamic or static binding, and either way it's more efficient for the runtime environment than comparing individual characters in a string.
Surely the switch on String would compile down to a String comparison (one per case) which is slower than a type comparison (and far slower than the typical integer compare that is used for switch/case)?
Three thoughts:
1) If you're going to do something different based on the types of the objects, it might make sense to move that behavior into those classes. Then instead of switch or if-else, you'd just call childNode.DoSomething().
2) Comparing types will be much faster than string comparisons.
3) In the if-else design, you might be able to take advantage of reordering the tests. If "Jill" objects make up 90% of the objects going through there, test for them first.
One of the issues you have with the switch is using strings, like "Bob", this will cause a lot more cycles and lines in the compiled code. The IL that is generated will have to declare a string, set it to "Bob" then use it in the comparison. So with that in mind your IF statements will run faster.
PS. Aeon's example wont work because you can't switch on Types. (No I don't know why exactly, but we've tried it an it doesn't work. It has to do with the type being variable)
If you want to test this, just build a separate application and build two simple Methods that do what is written up above and use something like Ildasm.exe to see the IL. You'll notice a lot less lines in the IF statement Method's IL.
Ildasm comes with VisualStudio...
ILDASM page - http://msdn.microsoft.com/en-us/library/f7dy01k1(VS.80).aspx
ILDASM Tutorial - http://msdn.microsoft.com/en-us/library/aa309387(VS.71).aspx
Remember, the profiler is your friend. Any guesswork is a waste of time most of the time.
BTW, I have had a good experience with JetBrains' dotTrace profiler.
Switch on string basically gets compiled into a if-else-if ladder. Try decompiling a simple one. In any case, testing string equailty should be cheaper since they are interned and all that would be needed is a reference check. Do what makes sense in terms of maintainability; if you are compring strings, do the string switch. If you are selecting based on type, a type ladder is the more appropriate.
I kind of do it a bit different,
The strings you're switching on are going to be constants, so you can predict the values at compile time.
in your case i'd use the hash values, this is an int switch, you have 2 options, use compile time constants or calculate at run-time.
//somewhere in your code
static long _bob = "Bob".GetUniqueHashCode();
static long _jill = "Jill".GetUniqueHashCode();
static long _marko = "Marko".GeUniquetHashCode();
void MyMethod()
{
...
if(childNode.Tag==0)
childNode.Tag= childNode.Name.GetUniquetHashCode()
switch(childNode.Tag)
{
case _bob :
break;
case _jill :
break;
case _marko :
break;
}
}
The extension method for GetUniquetHashCode can be something like this:
public static class StringExtentions
{
/// <summary>
/// Return unique Int64 value for input string
/// </summary>
/// <param name="strText"></param>
/// <returns></returns>
public static Int64 GetUniquetHashCode(this string strText)
{
Int64 hashCode = 0;
if (!string.IsNullOrEmpty(strText))
{
//Unicode Encode Covering all character-set
byte[] byteContents = Encoding.Unicode.GetBytes(strText);
System.Security.Cryptography.SHA256 hash = new System.Security.Cryptography.SHA256CryptoServiceProvider();
byte[] hashText = hash.ComputeHash(byteContents);
//32Byte hashText separate
//hashCodeStart = 0~7 8Byte
//hashCodeMedium = 8~23 8Byte
//hashCodeEnd = 24~31 8Byte
//and Fold
Int64 hashCodeStart = BitConverter.ToInt64(hashText, 0);
Int64 hashCodeMedium = BitConverter.ToInt64(hashText, 8);
Int64 hashCodeEnd = BitConverter.ToInt64(hashText, 24);
hashCode = hashCodeStart ^ hashCodeMedium ^ hashCodeEnd;
}
return (hashCode);
}
}
The source of this code was published here
Please note that using Cryptography is slow, you would typically warm-up the supported string on application start, i do this my saving them at static fields as will not change and are not instance relevant. please note that I set the tag value of the node object, I could use any property or add one, just make sure that these are in sync with the actual text.
I work on low latency systems and all my codes come as a string of command:value,command:value....
now the command are all known as 64 bit integer values so switching like this saves some CPU time.
I was just reading through the list of answers here, and wanted to share this benchmark test which compares the switch construct with the if-else and ternary ? operators.
What I like about that post is it not only compares single-left constructs (eg, if-else) but double and triple level constructs (eg, if-else-if-else).
According to the results, the if-else construct was the fastest in 8/9 test cases; the switch construct tied for the fastest in 5/9 test cases.
So if you're looking for speed if-else appears to be the fastest way to go.
I may be missing something, but couldn't you do a switch statement on the type instead of the String? That is,
switch(childNode.Type)
{
case Bob:
break;
case Jill:
break;
case Marko:
break;
}