RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

switching with 2 variables

poorchava

Wanderer
switching with 2 variables

Can i use switch with more than one argument? I mean something like this:
Code:
switch(a,b)
{
case 1,5:P{some stuff}
case 1,6:P{some stuff}
case 1,7:P{some stuff}
case 2,5:P{some stuff}
case 3,5:P{some stuff}

}
 

Courageous

Wanderer
You could, theoretically, concatenate your numbers together into a single string, and then case on the stringified permutations.

case "a,b": ...

Kind of ugly, possibly slow.

There are of course a fair number of other ways to do this, but nothing quite so compact and elegant as the thing you asked if you could do.

If you could do it (which you can't), it would be because C# would have a language native form called a "tuple". Languages that do have tuples allow this sort of thing, and more. Another example of something that you can do with tuple supporting languages is this:

a, b = myfunction();

Or also:

(a, b) += (1, 2);

And of course, the case you mentioned:

switch( a, b ) {
case( 1, 2) :
...

But alas, can't do any of these in C#. Would be nice if you could!

C//
 

daat99

Moderator
Staff member
Code:
if ( a==1)
{
   if (b==5)
      stuff
   else if (b==6)
      stuff
   else if (b==7)
      stuff
}
else if (b==5)
{
   if (a==2)
      stuff
   else if (a==3)
      stuff
}
That's the shortest way I know of doing what you want in c#.
If someone know of a better way than PLEASE let me know too.
 

Vindekator

Sorceror
You might try something like

switch(slct[a,b])
{
case "1_5":p{some stuff}
case "1_6":p{some stuff}
case "1_7":p{some stuff}
case "2_5":p{some stuff}
case "3_5":p{some stuff}
}

where you have set up the array slct to have the values required (also include a default if necessary)

You can increment or set your indexes and get a testable string from the array.
 

daat99

Moderator
Staff member
Vindekator said:
You might try something like

switch(slct[a,b])
{
case "1_5":p{some stuff}
case "1_6":p{some stuff}
case "1_7":p{some stuff}
case "2_5":p{some stuff}
case "3_5":p{some stuff}
}

where you have set up the array slct to have the values required (also include a default if necessary)

You can increment or set your indexes and get a testable string from the array.
If you're going this way you may want to skip the array and just do:
Code:
switch (a+","+b)
{
   case "1,5": bla bla
   case "1,6": bla bla
   case "1,7": bla bla
   case "2,5": bla bla
   case "3,5": bla bla
}
Same effect but you don't need to declare and set values in a string array.
Keep in mind that working with strings (or string array) use a lot of cpu power and is definatly not advised.
 

noobie

Wanderer
I wouldnt want to go over any code you guys have written :)

Speed is really irrevelant in such a case and you cant really say shorter code is the fastest one.

I would write it as clear as possible and in a more logical way.

this is clear but it is not logical
Code:
if ( a==1)
{
   if (b==5)
      stuff
   else if (b==6)
      stuff
   else if (b==7)
      stuff
}
else if (b==5)
{
   if (a==2)
      stuff
   else if (a==3)
      stuff
}

just use:
Code:
if (a==1)
//bla bla
else
//..

or
Code:
if (a==xx && b==zz)
else if ..
 

Courageous

Wanderer
Code:
if (a==xx && b==zz)
else if ..

I think the above is the clearest and most legible. Your prior remark about having just one check for a with all the b checks embedded was correct as well. Generally the beginner should start with that form before chaining logical ands together (as you show above), on the grounds that the results can be a bit confounding in more complicated cases.

C//
 

xir

Wanderer
I beleive switches are generally faster than chained if statements, especially if you have loads of them. To my knowledge switches are placed into a lookup table with an offset. After the comparison is done the program counter is set to the piece of code.

P.S. Found a reference
http://en.wikipedia.org/wiki/Jump_table
 

Courageous

Wanderer
It may or may not be that switches are sometimes unrolled to loop tables. However, until one knows the performance concerns of a section of code, one should write code principally for other humans, and not the computer. Agreeably, switch is often pretty clear.

C//
 

noobie

Wanderer
I really doubt using switch with string concat would much faster than regular a few if-else statements. btw it also has to build that look up table.

anyway event it were faster, does it really matter? how faster could it make it in such a simple case?? nanoseconds??
 

daat99

Moderator
Staff member
noobie said:
I really doubt using switch with string concat would much faster than regular a few if-else statements. btw it also has to build that look up table.

anyway event it were faster, does it really matter? how faster could it make it in such a simple case?? nanoseconds??
On the countrary, using a string will be a lot slower than if/else.
When you do a lot of string operations you really use a lot more cpu than you may think, you should really avoid string operations where possible.
 

Courageous

Wanderer
Contatenating the strings is relatively expensive.

Checking for ==/!= is one instruction, even for strings, because C# strings are internalized. An internalized string is essentially a pointer to a string in a table, such that, at any given time, two strings that are spelled the same are actually the same object. If they have the same address, they are the same string, and if they don't, they aren't. So C# just compares their (internal) memory addresses. One instruction for that, basically. Very fast.

Hacking the strings together prolly isn't a good idea. Some set of ifs is the right way to do this.

C//
 

noobie

Wanderer
Actually, as far as I know strings in .NEt has an exception for that. It overloads == operator and calls Object.Equal() method for comparisons. So it shouldnt compare the references but objects itself.

Anyway what I meant was actually crappy code vs speed. If you are doing a large amount of iterations, you could change it if it gets faster but otherwise it is not worth it since it compeletely loses its readibility..
 

Courageous

Wanderer
The default implementation of Equal for strings is a reference comparison. C# internalizes strings for exactly this performance related reason. The following test confirms this, as there is only a minor difference between the two performance tests, where, if string matching were being performed, the two tests would very greatly in times (they do not).

Code:
using System;
using System.Collections;
using System.Collections.Generic;
//------------------------------------------------------------------------------
public class Test
{
    private static int[,]  m_Integers = new int[,]
    {
        {  1,  3 },
        {  3,  3 },
        {  3,  5 },
        {  5,  5 },
        {  5,  7 },
        {  7,  7 },
        {  7, 11 },
        { 11, 11 },
        { 11, 13 },
        { 13, 13 },
    };
    private static string[,]  m_Strings = new string[,]
    {
        { "thisisaridculouslylongstring_one",      "thisisaridculouslylongstring_three" },
        { "thisisaridculouslylongstring_three",    "thisisaridculouslylongstring_three" },
        { "thisisaridculouslylongstring_three",    "thisisaridculouslylongstring_five" },
        { "thisisaridculouslylongstring_five",     "thisisaridculouslylongstring_five" },
        { "thisisaridculouslylongstring_five",     "thisisaridculouslylongstring_seven" },
        { "thisisaridculouslylongstring_seven",    "thisisaridculouslylongstring_seven" },
        { "thisisaridculouslylongstring_seven",    "thisisaridculouslylongstring_eleven" },
        { "thisisaridculouslylongstring_eleven",   "thisisaridculouslylongstring_eleven" },
        { "thisisaridculouslylongstring_eleven",   "thisisaridculouslylongstring_thirteen" },
        { "thisisaridculouslylongstring_thirteen", "thisisaridculouslylongstring_thirteen" },
    };
//------------------------------------------------------------------------------
    
    public static void Main( string[] args )
    {
        {
            double  start = DateTime.Now.Ticks / 10000000.0;

            long count = 0;
            for( long i=0; i<100000000; i++)
            {
                int index = (int)( i % 10L );

                if( m_Integers[index,0]==m_Integers[index,1] ) count++;
            }
            double  stop = DateTime.Now.Ticks / 10000000.0;
            double  elapsed = stop - start;

            Console.WriteLine("INTEGERS");
            Console.WriteLine("    count: "+count);
            Console.WriteLine("    elapsed: "+elapsed);
        }
        {
            double  start = DateTime.Now.Ticks / 10000000.0;

            long count = 0;
            for( long i=0; i<100000000; i++)
            {
                int index = (int)( i % 10L );

                if( m_Strings[index,0]==m_Strings[index,1] ) count++;
            }
            double  stop = DateTime.Now.Ticks / 10000000.0;
            double  elapsed = stop - start;

            Console.WriteLine("STRINGS");
            Console.WriteLine("    count: "+count);
            Console.WriteLine("    elapsed: "+elapsed);
        }
    }
}
//------------------------------------------------------------------------------

On my computer, I (correctly) calculate 50,000,000 matches for each case, but case one takes 3.70 seconds, and case two takes 4.65. The difference in times is probably associated with the function dispatch, but then recouped by the reference (pointer address) compare. I should imagine that if Int were used instead of the primitive int, these tests would come out the same.

C//
 

noobie

Wanderer
C, I dont get the point with your code..

I dont have any compiler right now but try these ones:

string a="mystr";
string b="mystr";

Console.WriteLine(a==b); //true
Console.WriteLine(a.Equals(b)); //true


however then try this one:

int x=5;

Console.WriteLine((Object)x == (Object)x); //false
Console.WriteLine(x.Equals(x)); //true


and finally try this one:
Object x=5;
Object y=5;

Console.WriteLine(x==y); //false
Console.WriteLine(x.Equals(y)); //true


So string camparisons with == operator is different than others.

(I couldnt test it.Let me know if any results is not same with mine)
 

Courageous

Wanderer
C, I dont get the point with your code...

If it were having to compare every letter of the string, it would have to be many times slower, but it's not. The difference between 100,000,000 compares in the two sets of code is only 1 second. It does address compares (under the hood), with some added overhead. QED.

C//
 

noobie

Wanderer
Small difference doesnt mean it uses references to compare.And why should it mean something like that?? integer comparisons dont use reference comparisons..

This is just a guess, I'll look into it but I think for integer comparisons, it box the value and then calls Int32.Equals() method. Thats why the difference is not huge. Another reason could be caching and optimization done by CLR since none of those variables hasnt change.


Anyway, if you compare my first and third examples, I think it is very clear..
 

Courageous

Wanderer
Small difference doesnt mean it uses references to compare. And why should it mean something like that?

See quote below.


integer comparisons dont use reference comparisons..
Integers don't need to. They are a unique number. You can use a single assembler instruction to compare them per se. Strings don't have that property on any modern silicon I know of. So they are "internalized" in such a fashion that any two strings that are spelled the same (are "lexigraphically identical" is the technical term) have the same address in memory. You can then know that if the address is the same, they are the same string, and if not, not.

C# internalizes strings and does reference comparison for equality check by default. Why? Because it's the only fast way to do this. It's also memory-compact, which is why any virtual machine worth its salt always uses string internalization.

But by all means, don't believe me. Here's a direct quote from MSDN:



The common language runtime conserves string storage by maintaining a table, called the intern pool, that contains a single reference to each unique literal string declared or created programmatically in your program. Consequently, an instance of a literal string with a particular value only exists once in the system. For example, if you assign the same literal string to several variables, the runtime retrieves the same reference to the literal string from the intern pool and assigns it to each variable.

I suppose, thinking about it, it would be possible to assign a unique number to a master object, and compare that number itself. Same/same. And kind of pointless. The address of any object in the table is a unique number itself.





C//
 

noobie

Wanderer
What you are saying basicly is "str"=="str" returns false..

Normally, Equals method compare the objects by value and == operator compares them by reference

I am pretty sure it doesnt use references to compare. As I said before, string class overloads == operator and calls Equals() method. Easiest way would be just checking IL code of String class by a disassembler but I dont have even .net framework right now :)
 
Top