Converting bunch of if else statements to an efficient data structure

So i got this every Lateupdate:

        transform.parent.gameObject.layer = hit.transform.gameObject.layer;
	    if(transform.parent.gameObject.layer == 10)
			shadowProjector.ignoreLayers = ~((1 << 10) + (1 << 21) + (1 << 9));
		else if(transform.parent.gameObject.layer == 11)
			shadowProjector.ignoreLayers = ~((1 << 11) + (1 << 21) + (1 << 22) + (1 << 9));
		else if(transform.parent.gameObject.layer == 12)
			shadowProjector.ignoreLayers = ~((1 << 12) + (1 << 22) + (1 << 23) + (1 << 9));
		else if(transform.parent.gameObject.layer == 13)
			shadowProjector.ignoreLayers = ~((1 << 13) + (1 << 23) + (1 << 24) + (1 << 9));
		else if(transform.parent.gameObject.layer == 14)
			shadowProjector.ignoreLayers = ~((1 << 14) + (1 << 24) + (1 << 25) + (1 << 9));
		else if(transform.parent.gameObject.layer == 15)
			shadowProjector.ignoreLayers = ~((1 << 15) + (1 << 25) + (1 << 26) + (1 << 9));
		else if(transform.parent.gameObject.layer == 16)
			shadowProjector.ignoreLayers = ~((1 << 16) + (1 << 26) + (1 << 27) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 17)
			shadowProjector.ignoreLayers = ~((1 << 17) + (1 << 27) + (1 << 28) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 18)
			shadowProjector.ignoreLayers = ~((1 << 18) + (1 << 28) + (1 << 29) + (1 << 9));
		else if(transform.parent.gameObject.layer == 19)
			shadowProjector.ignoreLayers = ~((1 << 19) + (1 << 29) + (1 << 30) + (1 << 9));
		else if(transform.parent.gameObject.layer == 20)
			shadowProjector.ignoreLayers = ~((1 << 20) + (1 << 30) + (1 << 9));
		else if(transform.parent.gameObject.layer == 21)
			shadowProjector.ignoreLayers = ~((1 << 21) + (1 << 10) + (1 << 11) + (1 << 9));
		else if(transform.parent.gameObject.layer == 22)
			shadowProjector.ignoreLayers = ~((1 << 22) + (1 << 11) + (1 << 12) + (1 << 9));
		else if(transform.parent.gameObject.layer == 23)
			shadowProjector.ignoreLayers = ~((1 << 23) + (1 << 12) + (1 << 13) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 24)
			shadowProjector.ignoreLayers = ~((1 << 24) + (1 << 13) + (1 << 14) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 25)
			shadowProjector.ignoreLayers = ~((1 << 25) + (1 << 14) + (1 << 15) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 26)
			shadowProjector.ignoreLayers = ~((1 << 26) + (1 << 15) + (1 << 16) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 27)
			shadowProjector.ignoreLayers = ~((1 << 27) + (1 << 16) + (1 << 17) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 28)
			shadowProjector.ignoreLayers = ~((1 << 28) + (1 << 17) + (1 << 18) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 29)
			shadowProjector.ignoreLayers = ~((1 << 29) + (1 << 18) + (1 << 19) + (1 << 9));	
		else if(transform.parent.gameObject.layer == 30)
			shadowProjector.ignoreLayers = ~((1 << 30) + (1 << 19) + (1 << 20) + (1 << 9));

Seems to me that I can convert the if else statements to a dictionary type thing because it would be WAY more efficient to have a direct reference from a transform.parent.gameObject.layer to a shadowProjector.ignoreLayers value instead of doing if elses.

So could i initialize the dictionary in the Awake() function and then replace all the if elses with one line: shadowProjector.ignoreLayers = CurrentDict(“transform.parent.gameObject.layer”);

If i were to use a dictionary though, would it go from int to int?
Can i store ~((1 << 10) + (1 << 21) + (1 << 9)) as an int?
It’s much more readable for me to leave it in that format where i can clearly see where the bits are being shifted instead of simplifying to an integer value.

And is dictionary even the best approach or should i use Enums or a fixed size array or something else? What’s the most efficient structure for this?

Hashtables or Dictionaries are really great datastructures, but not in this case. They create several arrays of KeyValuePairs (so called buckets) and put your key / values into those arrays. Hashtables are ment for huge amount of data. 32 values are nothing. In this case it would be very inefficient (memory-wise and performance-wise).

Since your incoming value is between 0 and 31 the best solution is simply an ordinary static array.

// C#
public static int[] layerMapping = new int[]
{
    /* 0*/ 0,
    /* 1*/ 0,
    /* 2*/ 0,
    /* 3*/ 0,
    /* 4*/ 0,
    /* 5*/ 0,
    /* 6*/ 0,
    /* 7*/ 0,
    /* 8*/ 0,
    /* 9*/ 0,
    /*10*/ ~((1 << 10) | (1 << 21) | (1 << 9)),
    /*11*/ ~((1 << 11) | (1 << 21) | (1 << 22) | (1 << 9)),
    /*12*/ ~((1 << 12) | (1 << 22) | (1 << 23) | (1 << 9)),
    /*13*/ ~((1 << 13) | (1 << 23) | (1 << 24) | (1 << 9)),
    /*14*/ ~((1 << 14) | (1 << 24) | (1 << 25) | (1 << 9)),
    /*15*/ ~((1 << 15) | (1 << 25) | (1 << 26) | (1 << 9)),
    /*16*/ ~((1 << 16) | (1 << 26) | (1 << 27) | (1 << 9)),
    /*17*/ ~((1 << 17) | (1 << 27) | (1 << 28) | (1 << 9)),
    /*18*/ ~((1 << 18) | (1 << 28) | (1 << 29) | (1 << 9)),
    /*19*/ ~((1 << 19) | (1 << 29) | (1 << 30) | (1 << 9)),
    /*20*/ ~((1 << 20) | (1 << 30) | (1 << 9)),
    /*21*/ ~((1 << 21) | (1 << 10) | (1 << 11) | (1 << 9)),
    /*22*/ ~((1 << 22) | (1 << 11) | (1 << 12) | (1 << 9)),
    /*23*/ ~((1 << 23) | (1 << 12) | (1 << 13) | (1 << 9)),
    /*24*/ ~((1 << 24) | (1 << 13) | (1 << 14) | (1 << 9)),
    /*25*/ ~((1 << 25) | (1 << 14) | (1 << 15) | (1 << 9)),
    /*26*/ ~((1 << 26) | (1 << 15) | (1 << 16) | (1 << 9)),
    /*27*/ ~((1 << 27) | (1 << 16) | (1 << 17) | (1 << 9)),
    /*28*/ ~((1 << 28) | (1 << 17) | (1 << 18) | (1 << 9)),
    /*29*/ ~((1 << 29) | (1 << 18) | (1 << 19) | (1 << 9)),
    /*30*/ ~((1 << 30) | (1 << 19) | (1 << 20) | (1 << 9)),
    /*31*/ 0
};

Now you can simply use the layer variable as index into this array. This is the fastest lookup you can perform. And this array takes only 128 bytes of memory. Since it contains constant data it can be static so every script that needs it can use it.

ps: Never use “+” to join bitfields. If you accidently have the same value twice it would form the next greater. Always use the binary or “|”.

1 | 1 == 1
1 + 1 == 2
1 | 2 | 4 | 2 == 7
1 + 2 + 4 + 2 == 9

Is it a rule that everything must always use 9 and itself? If so, just leave those out of the list and always add them to everything. It seems like the other numbers follow a pattern, so a formula (with 1 or 2 ifs) is better than a table.

for a table, maybe a string with the layer numbers, like “10/21/9”?:

LayerTable[10] = "10/21/9";
// etc...

string w = LayerTable[n];
string[] nums = w.Split("/");
int mask = 0;
// add in each layer:
for(int i=0;i<nums.Length;i++)
  mask += 1<< int.Parse( nums *);*

Without seeing all of your code, I cannot say if my solution is overkill. If you have other behavior dependent on the layer number as well, or your layer number is part of a more complicated system, it might save you a lot of headaches. Otherwise it’ll just end up causing a lot of clutter.

Basically, you should make a class for each different layer that you have behavior for. Then have an interface ( ILayerIgnorer or some such) which contains the necessary method declarations; in this case void SetIgnoreLayers();. Each different layerclass then implements that interface and provides the correct layer to ignore.

If you have a lot of behavior dependent on the layer number you can pack all that functionality and data into those classes made specifically for the layers. Whereas if you only have your layer number and it is not (part of) a domain concept, you will end up with several classes + an interface that have only one method in them. That is just clutter.

A good way to test this is to try to come up with names for the layers. If the only thing you can think of are “Layer1”, “Layer2”, etc. then this solution was overkill. If you can EASILY think of, say “ProjectileIgnoreLayer” “TreeIgnoreLayer”, etc. then this solution might work for you.

http://answers.unity3d.com/questions/217024/please-explain-a-switch-statement.html

Instead of doing if else if else you can place your checking int (==1, ==2 etc) as your switch testing variable and specify cases for each answer. This means it would jump straight to the case you wanted. It is also possible to stack switch cases so you can make it perform multiple cases (not sure about Unityscript!). Also you get a default case, which is very useful.

You can also specify execution code in the cases, so not just to select variables but also to perform a function if a separate one is needed per case.

Ouch!

What about something like this:

using System.Collections.Generic;

public class YourClass : MonoBehaviour
{
    private Dictionary<int, Action> _ignoreLayersActions;

    void Awake()
    {
         _ignoreLayersActions = new Dictionary<int, Action>();

         // I'm only going to write one out here... 
         _ignoreLayersActions[10] = () => { 
            shadowProjector.ignoreLayers = ~((1 << 10) + (1 << 21) + (1 << 9)); 
        }
        // Repeat all of your cases here, or somewhere else.
    }

    void Update()
    {
         int layer = transform.parent.gameObject.layer;

         if (_ignoreLayersActions.ContainsKey(layer)
         {
             // This will run the anonymous function that we defined above.
             _ignoreLayersActions[layer]();
         }
    }
}