Checking set of values for combination - c#

So, I am using a group of enums to determine the value of 4 slots. There is one called none, and then 4 called fire,earth,water,air. The values of the slots are held in a dictionary of an integer as the index and the enum as the value. I want to check the values of this dictionary to see if certain combinations are present. I am not sure how to go about doing this most effectively without hard coding every situation. I know how I could store the combinations, but I am not exactly sure how to go about checking that against the values effectively.
The idea is if the combination is fire, fire, fire, fire, then it sets off a certain event/function.

I'm a little confused about the dictionary because it sounds like you're just using the keys to indicate the sequence. I'm guessing this is a SortedDictionary<int, Elements> (although it may not matter.) But first:
To compare any two lists you can use SequenceEquals.
Let's say this is your enum:
enum Elements { None, Fire, Earth, Water, Air }
Let's say the combination you're checking for is:
var elementsToMatch = new Elements[] { Elements.Fire, Elements.Fire, Elements.Fire };
You could do this:
var matches = dictionary.Values.SequenceEquals(elementsToMatch);
It's true if both sets contain the same elements in the same sequence, otherwise false.
If the sequence isn't important, just the combination of elements, then you could sort them first:
var matches = dictionary.Values.OrderBy(v=>v)
.SequenceEquals(elementsToMatch.OrderBy(e=>e));
Is a Dictionary necessary to do this?
You could do this:
var elements = new Dictionary<int, Elements>(); // or SortedDictionary
elements.Add(0, Elements.None);
elements.Add(1, Elements.Fire);
// etc.
Or you could do this:
var elements = new Elements[] { Elements.None, Elements.Water };
Or use a List<Elements>.
In any case the way you access it will be exactly the same:
elements[0]
elements[1]
// etc
With a dictionary it's possible that a key could be missing. There might be an elements[0] and elements[2] but no elements[1].
If the only reason for the Dictionary is to provide a position for each element then you could use an array or a list, because each element can already be referenced by its position.

Related

Sizing a List and referencing variable positions in a List C#

Needed to store many varbiables and at first went with an array, but I had errors when I tried to resize the amount of positions in an array with a separate variabe. Looked online and people said, better use a List.
I have but very confusing to use. Trying to use it logically but I'm just not getting it.
So I set up my list:
public List<int> TESTValues = new List<int>(10);
And to me logically, there should be a list on 10 positions but there isn't, it's empty. Only does it add a variable if I use: TESTValues.Add(1); which only adds 1 new variable in the next available position which is 1 when it should be position 11 right?
Let's say I would somehow get a list of 10 variables, how would I then reference a variable in position 8 of the list, even update it? I tried to use something like: TESTValues.IndexOf(8) = 40; sadly that does not work.
Anyone have a good understanding of these Lists and how I could get to use them? Explain them? Was expecting a List to be simpley than an Array, seems the other way round right now.
Capacity != Size (Count)
Gets or sets the total number of elements the internal data structure can hold without resizing.
The initial capacity given to the constructor has only one purpose: Immediate allocation.
Usually by default a List<T> starts with an initial capacity of 4. Under the hood it simply stores the values in an array.
Then every time you add elements and the new size would exceed the capacity then the underlying array is copied into a new array with double of the original size (= capacity of the list).
The "size" (= Count of the list) only grows by adding elements!
Gets the number of elements contained in the List<T>.
Now the only way to initialize a list with already 10 elements is by using another collection like e.g.
var yourList = new List<int>(new int[10]);
of course this requires the allocation of an array => work for the GC but if you do this only once probably not very problematic.
or using Linq you could also do
using System.Linq;
...
var yourList = Enumerable.Repeat(0, 10).ToList();

A sorted dictionary where it is easy to move to the next key

I have an ordered set of key-value pairs, for example with the following entries:
1 "one"
2 "two"
4 "four"
50 "fifty"
I would like to have a quick lookup (so given an int key, I want to find the value for that key), but also ideally have a quick way of finding the next key in the dictionary from a current key - so that given the key 2, find that the next key is 4, and then 50.
I know that a Dictionary does the first one quickly, and something like a linked-list for the second part too (but it's difficult to 'jump in' to start at a specific key).
I've had a look here, and it seems like some of this might be possible with a sorted dictionary? I wondered if there is a good data structure in C# to do both of these things (lookup by key and moving to the next key)?
I don't need the number of items to be very large (maybe in the thousands), but if possible, I would like to do a large number of lookups and move forward between keys quickly (without checking wheter 5, 6, 7... are present in the dictionary).
What you are looking for is OrderedDictionary in System.Collections.Specialized
In this collection you can get Key, and you can take item at next index next to already to found one, but out of the box implementation from Microsoft won't work, since its missing all required by you methods like TryGetValue or IndexOf.
Have a look at those pages:
MSDN
Custom ordered dictionary
You could put the info in your Value:
public class MyValue
{
string Value;
int NextId;
int PreviousId;
}
public Dictionary<int, MyValue>();
It's then trivial to get your previous or next id. It's then trivial to get your next or previous value.
Of course, the insert logic requires you to update the previous & next each time you add something.
SortedList is suitable for this.
SortedList<int, string> sortedList = new SortedList<int,string>();
sortedList.Add(1, "one");
sortedList.Add(2, "two");
sortedList.Add(4, "four");
sortedList.Add(50, "fifty");
int currentIndex = sortedList.Keys.IndexOf(2);
Console.WriteLine(sortedList.Keys[currentIndex+1]);
Console.WriteLine(sortedList.Values[currentIndex+1]);

Dictionary element accessing

Question
Must looping through all C# Dictionary elements be done only through foreach, and if so why?
Or, I could ask my question as: can Dictionary elements be accessed by position within the Dictionary object (i.e., first element, last element, 3rd from last element, etc)?
Background to this question
I'm trying to learn more about how Dictionary objects work, so I'd appreciate help wrapping my mind around this. I'm learning about this, so I have several thoughts that are all tied into this question. I'll try to present in a way that is appropriate for SO format.
Research
In a C# array, elements are referenced by position. In a Dictionary, values are referenced by keys.
Looking through the documentation on MSDN, there are the statements
"For purposes of enumeration, each item in the dictionary is treated as a
KeyValuePair structure representing a value and its key. The
order in which the items are returned is undefined."
So, it would seem that since the order items are returned in is undefined, there is no way to access elements by position. I also read:
"Retrieving a value by using its key is very fast, close to O(1),
because the Dictionary class is implemented as a hash table."
Looking at the documentation for the HashTable .NET 4.5 class, there is reference to using a foreach statement to loop through and return elements. But there is no reference to using a for statement, or for that matter while or any other looping statement.
Also, I've noticed Dictionary elements use the IEnumerable interface, which seems to use foreach as the only type of statement for looping functions.
Thoughts
So, does this mean that Dictionary elements cannot be accessed by "position," as arrays or lists can?
If this is so, why is there a .Count property that returns the number of key/value pairs, yet nothing that lets me reference these by nearness to the total? For example, .Count is 5, why can't I request key/value pair .Count minus 1?
How is foreach able to loop over each element, yet I have no access to individual elements in the same way?
Is there no way to determine the position of an element (key or value) in a Dictionary object, without utilizing foreach? Can I not tell, without mapping elements to a collection, if a key is the first key in a Dictionary, or the last key?
This SO question and the excellent answers touch on this, but I'm specifically looking to see if I must copy elements to an array or other enumerable type, to access specific elements by position.
Here's an example. Please note I'm not looking for a way to specifically solve this example - it's for illustration purposes of my questions only. Suppose I want to add all they keys in a Dictionary<string, string> object to a comma-separated list, with no comma at the end. With an array I could do:
string[] arrayStr = new string[2] { "Test1", "Test2" };
string outStr = "";
for (int i = 0; i < arrayStr.Length; i++)
{
outStr += arrayStr[i];
if (i < arrayStr.Length - 1)
{
outStr += ", ";
}
}
With Dictionary<string, string>, how would I copy each key to outStr using the above method? It appears I would have to use foreach. But what Dictionary methods or properties exist that would let me identify where an element is located at, within a dictionary?
If you're still reading this, I also want to point out I'm not trying to say there's something wrong with Dictionary... I'm simply trying to understand how this tool in the .NET framework works, and how to best use it myself.
Say you have four cars of different colors. And you want to be able to quickly find the key to a car by its color. So you make 4 envelopes labelled "red", "blue", "black", and "white" and place the key to each car in the right envelope. Which is the "first" car? Which is the "third"? You're not concerned about the order of the envelopes; you're concerned about being able to quickly get the key by the color.
So, does this mean that Dictionary elements cannot be accessed by "position," as arrays or lists can?
Not directly, no. You can use Skip and Take but all they will do is iterate until you get to the "nth" item.
If this is so, why is there a .Count property that returns the number of key/value pairs, yet nothing that lets me reference these by nearness to the total? For example, .Count is 5, why can't I request key/value pair .Count minus 1?
You can still measure the number of items even thought there's no order. In my example you know there are 4 envelopes, but there's no concept of the "third" envelope.
How is foreach able to loop over each element, yet I have no access to individual elements in the same way?
Because foreach use IEnumerable, which just asks for the "next" element each time - the underlying collection determines what order the elements are returned in. You can pick up the envelopes one by one, but the order is irrelevant.
Is there no way to determine the position of an element (key or value) in a Dictionary object, without utilizing foreach?
You can infer it by using foreach and counting how many elements you have before reaching the one you want, but as soon as you add or remove an item, that position may change. If I buy a green car and add the envelope, where in the "order" would it go?
I'm specifically looking to see if I must copy elements to an array or other enumerable type, to access specific elements by position.
Well, no, you can use Skip and Take, but there's no way to predict what item is at that location. You can pick up two envelopes, ignore them, pick up another one and call it the "third" envelope, but so what?
Several correct answers here, but I thought you might like a short version :)
Under the hood, the Dictionary class has a private field called buckets. It's just an ordinary array which maps integer positions to the objects you've added to the Dictionary.
When you add a key/value pair to the Dictionary, it calculates a hash value for your key. The hash value gets used as the index into the buckets array. The Dictionary uses as many bits of the hash as it needs to ensure that the index into the buckets array doesn't collide with an existing entry. The buckets array will be expanded as needed due to collisions.
Yes, it's possible via reflection (which allows you to extract private data fields) to get the 3rd, or 4th, or Nth member of the buckets array. But the array could be resized at any time and you're not even guaranteed that the implementation details of Dictionary won't change.
In addition to D Stanley's answer, I'd like to add that you should check out SortedDictionary<TKey, TValue>. It stores the key/value pairs in a data structure that does keep the keys ordered.
var d = new SortedDictionary<int, string>();
d.Add(4, "banana");
d.Add(2, "apple");
d.Add(7, "pineapple");
Console.WriteLine(d.ElementAt(1).Value); // banana
Looping through a dictionary does not need to be done using foreach, but the terms 'first,' and 'last' are meaningless in terms of a dictionary, because order is not guaranteed and is in no way related to the order items are added to your dictionary.
Think of it this way. You have a bag that you are using to store blocks, and each block has a unique label on it. Throw in a block with the labels "Foo," "Bar," and "Baz." Now, if you ask me what the count of my bag is, I can say I have 3 blocks in it and if you ask me for the block labeled "Bar" I can get it for you. However, if you ask me for the first block, I don't know what you mean. The blocks are just a jumble inside my bag. If, instead you say 'foreach' block, I'd like to take a photo of it, I'll hand you each block, 1 by 1. Again, the order isn't guaranteed. I'm just reaching into my bag and pulling out each block until I've gotten each one.
You can also ask for a collection of all the keys in a dictionary, then use each key to access the items in a dictionary. However, once again, the order of the keys is not guaranteed and, in theory, could change every time you access it (in practice, the .NET key order is normally pretty stable).
There's a lot of reasons why a dictionary is stored like this, but the key thing is dictionaries have to have unspecified order in order to have both O(1) insertion and O(1) access. An array, which has a specified order has O(1) access (you can get the n'th item in one step), but insertions are O(n).
There is a large number of collections available in the .Net framework. You have to analyse your requirements and decide which collection to use:
Do you need Key/Value pairs or just Items?
Is it important that items are sorted?
Do you need fast insertion or just add at start/end of collection?
Do you need fast retrieval: O(1) or O(log n)?
Do you need an index i.e. acces to items by an integer position?
For most combinations of these requirements there exists a specialized collection.
In your case: Key/Value pairs and acces through an index: SortedList

Array with negative indexes

I have an array which I'm using to store map data for a game I'm working on.
MyMapType[,,] map;
The reason I'm using a fixed array instead of a Collection is because fixed arrays work very much faster.
Now my problem is, I'd like to have support for negative z levels in the game. So I'd like to be able to access a negative index.
If this is not possible, I thought of a pair of other solutions.
I was thinking as a possible solution to have ground-level as some arbitrary number (say 10), and anything less than 10 could be considered negative. But wouldn't this make the array 10 times larger for nothing if its not in use?
Another solution I considered was to 'roll my own' where you have a Dictionary of 2D arrays, with the Z level held in the List as the index. But this is a lot more work and I'm not sure if its slow or not.
So to summarise - any way of creating an array which supports a negative index? And if there's not - is there a clean way of 'emulating' such behaviour without sacrificing too much CPU time or RAM - noting that these are game maps which could end up large AND need to be accessed constantly.
replace your arrays with a class:
class MyArray {
private MyMapType[] myArray = new myMapType[size]
MyMapType this[index] {
get{return myArray[index + offset];}
}
}
you can set the size and the offset in the constructor or even change it at will.
Building on this example here is another version:
class MyArray {
private MyMapType[] positives = new myMapType[size]
private MyMapType[] negatives = new myMapType[size-1]
MyMapType this[index] {
get{return index >= 0 ? positives[index] : negateves[1-index];}
}
}
It does not change the fact that you need to set the size for both of them. Honestly I like the first one better
If you want "negative" indexes C# 8 now supports it.
var words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumps", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
}; // 9 (or words.Length) ^0
So the to call the negative one would be like this
words[^1]
See this link
So in your case the middle element could be the zero Z
Use the Dictionary class, since you can assign whatever values you want for either the key or value. While I'm not sure how this would work for the 3-dimensional array that you showed above, I can show how this would work if this were a 1-dimensional array, and you can infer how to best make use of it:
MyMapType[] map;
//map is filled with w/e data
Dictionary<int, MyMapType> x = new Dictionary<int, MyMapType>();
x[-1] = //(map data for whatever value is for the negative value);
x[0] = map[0]
//(etc...)
Could you try to store a list of MyMapTime[,] in two lists:
one for z values of greater than or equal to 0
and second of negative z-values.
The index of the tables would be the value of z.
Having this would let you access quickly the xy-values for specific z-level.
Of course the question is: what are your z-values? Are there sparse or dense.
Even for sparse values you would end up with an array holding null values for [,].
I'd like to note here that dictionaries allow for negative indexes
and a 2D dictionairy can solve problems like these too, just think about the datastructure and if you can live with a dictionary
note that dictionaries and lists are used in different scenario's.
and their speed depends on what functions are used on them

String Array comparision and sorting

First off, i'd like to say that my programming knowledge is very basic and got a learn as you go style. So please bear with me if i sound stupid.
So i have a multi dimensional string array, a part of which is:
X Y
4,1 Adelaide
4,2 Interlagos
4,3 Sakhir
4,4 Hungaroring
4,5 Estoril
4,6 Barcelona
4,7 Silverstone
4,8 Mugello
4,9 Hockenheim
4,10 Monte Carlo
In the above table, X and Y are the 2 dimensions of the array.
Now i have another string array with elements from X dimension of the above array in unsorted fashion. For example,
4,6
5,15
3,7
10,12
etc...
Now what i want to do is write a code which looks into array #2 and assigns a corresponding element from dimension Y of the array #1.
For example, when the code encounters 4,6 in array #2, i want the code to assign the corresponding value which is Barcelona.
Just the basic snippet or algorithm is what i'm looking for. I'll do the rest myself.
Thanks in advance!
Sounds like table 1 should really be a Dictionary<string, string>, mapping "4,6" to "Barcelona". Then you can just do:
// However you want to populate your data
Dictionary<string, string> mapping = ...;
List<string> values = keys.Select(key => mapping[key]).ToList();
Note that this will throw an exception if any of the keys isn't mapped - if that's not what you want, please clarify the requirements.
It's not clear how you're getting this data, or whether your "multi-dimensional string array" is a string[,] or a string[][]. If you have to receive it as a string array, give us more details and we can explain how to convert that into the dictionary.
You should rather use a Dictionary for that. A dictionary is internally an array. If you hand over a key, value pair (to insert it) a so called hash function is applied to the key. This function returns an integer i. The value is than stored at array[i]. If you want to get a value from the Dictionary you hand over just the key. Internally the hash function is applied, i is computed and array[i] is returned. This sounds like very much overhead, but searching for the key is slow for large arrays (O(log n) if it is sorted by keys and O(n) if it is not sorted at all - if you know O notiation), where the hash function can be very fast in most applications. So even with large dictionaries accessing a value is fast. (There are some more tricks inside a dictionary, which handle the case that two keys result in the same integer i, but you don't have to care much about that, if you don't want to implement a dictionary yourself)
Dictionarys are also called maps or hashmaps in other languages.
Not sure if I'm interpreting your question correctly here...
Your array #2, are you saying you want to replace its elements(say "4,6") with "Barcelona"?If this is the case then:
Loop through array #2, for each element use String.split() to get the two numerical parts from it(ex. "4" and "6"). Then use Integer.parseInt() to convert them from String to ints(call them a,b) and use those ints as indexes to array #1 like array1[a][b] to get Y value.
I assume you really want to use an array because those numbers are small and bounded, otherwise use dictionary as suggest by other answers...
If you must receive your first set of data as a 2D array, here's how you can turn it into a dictionary:
Dictionary<string, string> dic = new Dictionary<string,string>();
for (int i = 0; i < firstArray.GetLength(0); i++)
{
dic.Add(firstArray[i, 0], firstArray[i, 1]);
}

Categories

Resources