Array with negative indexes - c#

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

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();

Using Lookup or Dictionary to represent a hand of cards in C#

I apologize if there is a similar question already out there. There
are several questions about scoring hands but I don't need that.
The project I am working on takes in 10 cards and needs to report the
best possible 5-card hand found ("straight", "high card", "flush"
etc.). Luckily what the actual hand of cards is is irrelevant, I just
need a name.
I've already parsed and sorted all the cards out and have the tests
for all the possible hands laid out. All I need now is a convenient
way to store the hands. My mad method is as follows, in pseudocode
terms:
I want to have a dynamic list horizontally that I can populate with the NUMBER values of the cards, in order from highest to lowest. For
example, "Q J T 7 4 2 1". T is 10. Duplicates of values will be
ignored. Next, I want each of those values to have, underneath, a
list of the suits of each value that exist in the deck. For example,
J will have a sub-list with the values "D H" to represent that I have
a Jack of Diamonds and a Jack of Hearts.
I believe this to be the most elegant way to deal with these cards,
since most poker hands deal with only values and this way I don't have
to worry about cards of the same value in a row for say the straight
test. Then the two tests that do deal with suit can easily be
tested for by referring to the values under the keys.
Take a deep breath, almost there.
So an instance of Lookup appears to be perfect! It has the exact "one
key to multiple values" structure that I want. However, it doesn't
allow me to add the suits as I come to them. I have to add them all
at once or not at all since the lists are immutable after entry.
So I either
have to find all the suits at once before I even make the Lookup
Somehow add values to the Lookup lists or
Use something else.
Any ideas on any of these?
UPDATE
TL;DR SPARKNOTES VERSION: How can I add more values to the keys inside of a Lookup?
*IMOPRTANT NOTE:*The output of this program should be a string containing the name of the highest hand possible, for example "four of a kind", "two pair" or "high card."
I found one solution (which I unfortunately lost the link to and can't find again) where they suggested re-creating the entire Lookup with the new list. It may just be me but I find that solution to be very... ugly... Anyway several other solutions I have explored or tested are to:
METHOD 1
Roll through and populate another array with the suits associated with each value. Basically (in actual pseudocode this time >_>):
Create an array of ArrayLists (array 1)
Iterate through a sorted string array of "cards" (array 2)
For each card:
Take the char at string index [1] (representing the suit) and add into the ArrayList in array 1 at the index number extracted from string index [0].
This way I have the list of values with associated suits that I wanted. And the list of suits is the minimal size to boot, making iteration through that easier later. With some extra steps I can even make the umbrella array an ArrayList and populate it with the card values in order so there are no gaps and no duplicate numbers. This will leave me with a jagged array of what I want. To be clear, this is not a homework assignment. However, it IS from a coding class project my roommate completed in the past which is why I have the constrictions and requirements I have. Someone else I asked told me SE gets plagued by these kinds of homework questions around this time, so I understand your skepticism. This is a personal project because I want to learn C# (all I know is Java right now, and I like the sound of parameter pointer passing in C# methods, which Java does not do).
If it WERE for a grade I would end there because it works. But I don't really like arraylists of arraylists, they seem messy to me. So I want to know if there is another method.
METHOD 2
I also considered simply dealing with duplicates that inevitably appear. For example, here is my test for a straight:
for (int i = 0; i < 5; i++)
{
int counter = 0;
for (int j = i; j < i + 4; j++)
{
int secondCard = getValue(cardsArray[j + 1]);
int firstCard = getValue(cardsArray[j]);
if (secondCard == firstCard)
{
break;
}
if (secondCard == (firstCard + 1))
{
counter++;
if (counter == 4)
{
isStraight = true;
return "straight";
}
}
}
}
This code does not work. It needs some tweaks somewhere or other to work completely but I want to analyze if it is worth it before I try to fix it. It DOES accurately test for a straight, though. Also a couple notes: firstCard and secondCard are there for readability and debug purposes, and isStraight is there so that I don't reinvent the wheel later when I test for a straight flush.
This nested loop will iterate through all the cards up till the 5th card (since you can't have a straight out of ten sorted cards with less than 5 cards) and then check the next five cards as you would expect. If during this iteration I encounter a duplicate entry it means that it's the same card of another suit and I simply "break". What SHOULD happen as a result of this one statement is that now we have incremented our second iteration by one to check the next card instead of the current one. The count of in-order cards that we have will stay the same so that a list like " 1D 2D 3S 3H 4D 5C" will skip over the second 3 when finding the straight. Despite the break I was actually quite pleased with the elegance of this solution, whether I had a right to be or not.
It all goes back to the flaws of using a simple array of strings ("cards"), which is what my code is tailored to right now. And I hate fixing issues, I'd rather avoid them. Maybe I'm being unnecessarily picky but I'm learning along the way.
METHOD 3
My consideration of the weaknesses of an array of strings lead me to Dictionaries, which looked attractive. It can easily be made to hold my values in order, and easy to find if I have a certain suit for a key (TryGet), all in a neat, tailor-made package. Creating multiple array lists and doing things like "(find index of my value); array1[index].Add(value)" would be replaced by "Dictionary.Add(value, suit)". But I can only add a suit to a key at the point of creation. I couldn't make a "2" key and add "S" and then when I find out the next card is a "2D" add a D under the "2" key. Dictionary just doesn't support that, or even adding multiple values at all. I can make a dictionary of lists, but I still can't edit the list since Dictionaries are mostly query data structures. Lookups support multiple values per key but still cannot be changed after the initial "Add()". Again I could "re-create" the entire lookup or dictionary to add a suit and keep everything in order. But to me that seems like rebuilding the whole bridge because this one cable is too long and I don't have an industrial able cutter. It's a problem that SHOULD have an easier solution, like maybe go and GET some cutters (import a class maybe?).
CONCLUSION
Since you suggest that my needs are no different than what a hand scoring system could deliver leads me to another question:
Are hand scores directly tied to certain hands? Like I mentioned earlier the result I want is "The best hand you can make is a full house" not "This player has the highest hand." So can I calculate the highest scoring hand and extrapolate a "full house" from that score? If so then I guess this is all unnecessary code, but I would kind of like to solve this anyway in that case.
As I wrote this edit it dawned on me that this is basically a vanity issue. I don't "like" the solution I have. I also don't want to use the accepted solution (table lookup) because that is not a coding project that is a copypaste project. I would greatly appreciate any input.
Let's do this the simplest way possible. First, say you have an array of 10 strings, each of which is the name of a card. Like "Four of Hearts" and "Queen of Spades". That's really inconvenient to work with. So the first thing we do is convert those strings to numbers to represent each card. A very convenient way to do it is to use numbers 0-12 for hearts, 13-25 for diamonds, etc. So you have code (possibly a lookup table) that converts names to numbers:
Ace of Hearts = 0
Two of Hearts = 1
Three of Hearts = 2
...
Queen of Hearts = 11
King of Hearts = 12
Ace of Diamonds = 13
...
...
Ace of Clubs = 26
...
...
Kind of Spades = 51
So you have an array of numbers that represents the 10 cards. Call it cardsArray:
int[] cardsArray = new int[10];
// here, fill the cards array from the input
It's easy to check for flushes if you sort by suit and value. Remember, there are only 10 cards, so sorting isn't going to take a huge amount of time. The sort is really easy:
int[] sortedBySuit =
cardsArray
.OrderBy(x => x/13) // sorts by suit
.ThenByDescending(x => x % 13) // then by value, descending
.ToArray();
You can then go sequentially through the array and determine if you have a flush, straight flush, and what the high card in the flush (if any) is.
You have to save that information, because four-of-a-kind beats a flush, for example. So you need to check that, too.
Next, sort by value:
int[] sortedByValue =
cardsArray
.OrderByDescending(x => x % 13)
.ToArray();
Now you can go sequentially through that list to determine high card, pairs, three of a kind, four of a kind, or straights. As you find each type of hand, you save that hand information ("king high straight" or "three tens", along with the hand's value [1 for high card, 2 for pair, straight, flush, full house, etc. in the proper order]) to a list.
Then you just pick the hand with the highest value from those that you found.
That's definitely not the fastest way to do things, but it's simple, uses very little memory, and is fast enough for a prototype. It's certainly simpler than using a dictionary or array of arrays, etc.
To be clear, I didn't read your novel.
TL;DR SPARKNOTES VERSION: How can I add more values to the keys inside of a Lookup?
Usually, when I need a "dictionary" with a key that has multiple values, I use a List<KeyValuePair<string, int>>. You could use LINQ to Objects to select all the values. For example:
static void StackOverflowExample()
{
var cardList = new List<KeyValuePair<string,int>> ()
{
new KeyValuePair<string, int>("Club", 8),
new KeyValuePair<string, int>("Spade", 9),
new KeyValuePair<string, int>("Heart", 10)
};
var results = cardList.Where(p => p.Key == "Heart");
}
var results is an IEnumerable<KeyValuePair<string,int>>. Hopefully, this helps.

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]);
}

How do I insert an int into a sorted array quickly?

I'd like to insert an int into a sorted array. This operation is going to be performed very often, so it needs to be as fast as possible.
It is possible and even preferred to use a List or any other class instead of an array
All values are in the 1 to 34 range
The array typically contains exactly 14 values
I was thinking of many different approaches, including binary search and simple insert-on-copy, but found it hard to decide. Also, I felt like I missed an idea. Do you have experiences on this topic or any new ideas to consider?
I will use an int array whose length is 35(because you said range 1-34) to record the status of the numbers.
int[] status = Enumerable.Repeat(0, 35).ToArray();
//an array contains 35 zeros
//which means currently there is no elements in the array
status[10] = 1; // now the array have only one number: 10
status[11] ++; // a new number 11 is added to the list
So if you want to add a number i to the list:
status[i]++; // O(1) to add a number
To remove an i from the list:
status[i]--; // O(1) to remove a number
Want to know all the numebrs in the list?
for (int i = 0; i < status.Length; i++)
{
if (status[i] > 0)
{
for (int j = 0; j < status[i]; j++)
Console.WriteLine(i);
}
}
//or more easier using LINQ
var result = status.SelectMany((i, index) => Enumerable.Repeat(index, i));
The following example may help you understand my code better:
the real number array: 1 12 12 15 9 34 // i don't care if it's sorted
the status array: status[1]=1,status[12]=2,status[15]=1,status[9]=1,status[34]=1
all others are 0
At 14 values this is a pretty small array, I don't think switching to a smarter data structure such as a list will win you much, especially if you fast good random access. Even binary search may actually be slower than linear search at this scale. Are you sure that, say, insert-on-copy does not satisfy your performance requirements?
This operation is going to be performed very often, so it needs to be as fast as possible.
The things that you notice happen "very often" are frequently not the bottlenecks in the program - it's often surprising what the actual bottlenecks are. You should code something simple and measure the actual performance of your program before performing any optimizations.
I was thinking of many different approaches, including binary search and simple insert-on-copy, but found it hard to decide.
Assuming that this is the bottleneck, the big-O performance of the different methods is not going to be relevant here because of the small size of your array. It is easier to just try a few different approaches, measure the results, see which performs best and choose that method. If you have followed the advice from the first paragraph you already have a profiler setup that you can use for this step too.
For inserting into the middle, a LinkedList<int> would be the fastest option - anything else involves copying data. At 14 elements, don't stress over binary search etc - just walk forwards to the item you want:
using System;
using System.Collections.Generic;
static class Program
{
static void Main()
{
LinkedList<int> data = new LinkedList<int>();
Random rand = new Random(12345);
for (int i = 0; i < 20; i++)
{
data.InsertSortedValue(rand.Next(300));
}
foreach (int i in data) Console.WriteLine(i);
}
}
static class LinkedListExtensions {
public static void InsertSortedValue(this LinkedList<int> list, int value)
{
LinkedListNode<int> node = list.First, next;
if (node == null || node.Value > value)
{
list.AddFirst(value);
}
else
{
while ((next = node.Next) != null && next.Value < value)
node = next;
list.AddAfter(node, value);
}
}
}
Doing the brute-force approach is the best decision here because 14 isn't a number :). However, this is not a scalable decision, since should 14 become 14000 one day that will cause problems
What is the most common operation with your array?
Insert? Read?
Heap data structure will give you O(log(14)) for both of them. SortedDictionary may hit your performance.
Using a simple array will give you O(1) for reading and O(14) for insert.
By the way, have you tried System.Collections.Generic.SortedDictionary ot System.Collections.Generic.SortedList?
If you're on .Net 4 you should take a look at the SortedSet<T>. Otherwise take a look at SortedDictionary<TKey, TValue> where you make TValue as object and just put null into it, cause you're just interested into the keys.
If there is no repeated value on the array and the possible values won´t change maybe a fixed size array where the value is equal to the index is a good choice
Both insert and read are O(1)
You have a range of possible values from 1-34 which is rather narrow. So the fastest way would likely be using an array with 34 slots. To insert a number n just do array[n-1]++ and to remove it do array[n.1]-- (if n>0).
To check if a value exists in your collection you do array[n-1]>0.
edit: Damn...Danny was faster. :)
Write a method takes an array of integers and sorts them in place using Bubble Sort. The method is not allowed to create any additional arrays. Bubble Sort is a simple sorting algorithm that works by looping through the array to be sorted, comparing each pair of adjacent elements and swapping them if they are in the wrong order.

Quickest way to determine if a 2D array contains an element?

Let's assume that I've got 2d array like :
int[,] my_array = new int[100, 100];
The array is filled with ints. What would be the quickest way to check if a target-value element is contained within the array ?
(* this is not homework, I'm trying to come up with most efficient solution for this case)
If the array isn't sorted in some fashion, I don't see how anything would be faster than checking every single value using two for statements. If it is sorted you can use a binary search.
Edit:
If you need to do this repeatedly, your approach would depend on the data. If the integers within this array range only up to 256, you can have a boolean array of that length, and go through the values in your data flipping the bits inside the boolean array. If the integers can range higher you can use a HashSet. The first call to your contains function would be a little slow because it would have to index the data. But subsequent calls would be O(1).
Edit1:
This will index the data on the first run, benchmarking found that the Contains takes 0 milliseconds to run after the first run, 13 to index. If I had more time I might multithread it and have it return the result, while asynchronously continuing indexing on the first call. Also since arrays are reference types, changing the value of data passed before or after it has been indexed will provide strange functionality, so this is just a sample and should be refactored prior to use.
private class DataContainer
{
private readonly int[,] _data;
private HashSet<int> _index;
public DataContainer(int[,] data)
{
_data = data;
}
public bool Contains(int value)
{
if (_index == null)
{
_index = new HashSet<int>();
for (int i = 0; i < _data.GetLength(0); i++)
{
for (int j = 0; j < _data.GetLength(1); j++)
{
_index.Add(_data[i, j]);
}
}
}
return _index.Contains(value);
}
}
Assumptions:
There is no kind of ordering in the arrays we can take advantage of
You are going to check for existence in the array several times
I think some kind of index might work nicely. If you want a yes/no answer if a given number is in the array. A hash table could be used for this, giving you a constant O(k) for lookups.
Also don't forget that realistically, for small MxN array sizes, it might actually be faster just to do a linear O(n) lookup.
create a hash out of the 2d array, where
1 --> 1st row
2 --> 2nd row
...
n --> nth row
O(n) to check the presence of a given element, assuming each hash check gives O(1).
This data structure gives you an opportunity to preserve your 2d array.
upd: ignore the above, it does not give any value. See comments
You could encapsulate the data itself, and keep a Dictionary along with it that gets modified as the data gets modified.
The key of the Dictionary would be the target element value, and the value would be the number of entries of the element. To test if an element exists, simply check the dictionary for a count > 0, which is somewhere between O(1) and O(n). You could also get other statistics on the data much quicker with this construct, particularly if the data is sparse.
The biggest drawback to this solution is that data modifications have more operations involved (still should be O(1), though), so if you're mostly doing data manipulation, then this might not be suitable.

Categories

Resources