List or Dictionary or something else? - c#

I want to save some coordinates in a dictionary, BUT the xPos should be twice or more in the dictionary.
The problem is that the following exception appears:
ArgumentException: An element with the same key already exists in the dictionary.
How can I solve the problem ?
I allready thought that I can use a List or an Array, but I want a Key and a Value.
After I saved the coordinates in a Dict (or something else) I want to check whether a new coordinate is a certain distance of the existing ones.
The xPos is allways the same:
There is a "chart" where I place some blocks in a row with different yPos.
1. Block: xPos = 0, yPos = random
2. Block: xPos = 1, yPos = random
...
n. Block: xPos = 80, yPos = random
n+1. Block: xPos = 0, yPos = 20 + random
I have three iterations, for each 80 Blocks are placed.
SORRY for my bad english :|
I hope you could understand.

Or you can use List of Tuple to store list of int-int pairs without creating new class and without worrying about duplicate values :
.....
List<Tuple<int, int>> blocks = new List<Tuple<int, int>>();
blocks.Add(Tuple.Create(0, random));
blocks.Add(Tuple.Create(1, random));
.....

You can create a class (or a struct) to keep and use your coordinates, instead of a dictionary.
The class can have Key and Value properties and also additional fields if needed.

You should save the values like List, where Position contains:
public int X { get; set; }
public int Y { get; set; }
Or you can use some another class/struct from C# or some 3rd libraries (2d vector, point, etc) depends on where you want to use it. :)

Since you're storing points in a 2-d surface and want to do nearest-point detection, I'd recommend using a Binary Space Partitioning (BSP) tree, such as a QuadTree. Here's a link to a quadtree implementation in C#.

Related

how to create multidimensional arrays in C# without knowing the size

I need to understand on a practical level how to create a matrix[][] in C# without knowing the size.
And consequently also how to modify it (delete elements depending on a search key).
I have an example loop. Two random string variables. Then I am no longer able to continue....
private static Random random = new Random();
for (int i=0; i<unKnown; i++){
var firstVar = RandomString(5);
var secondVar = RandomString(20);
//Matrix[][]
}
public static string RandomString(int length){
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
Thank you
Arrays are fixed size. They do not adjust their size automatically. E.g. the size is defined when creating the array with
string[] array = new string[10];
If your array is 2 dimensional (10x10) and you delete the value at (1:1) the Array still remains 10x10 but the field at 1:1 is null now.
If you need a solution that adjusts its size you might want to look into Lists.
Otherwise, I advise you to read the documentation.
It really depend on what you want to do.
If you want a 2D array of values you can use multidimensional arrays. This supports arbitrary dimensions, but for more dimensions data sizes tend to go up and other solutions might be preferable:
var matrix = new double[4, 2];
If you want to do math you might want to use a library like Math.Net with specialized matrix types:
var matrix = Matrix<double>.Build.Dense(4, 2);
If you want to do computer graphics you likely want to use a specialized library, like system.Numerics.Matrix4x4
var matrix = new Matrix4x4();
It is also not particularly difficult to create your own matrix class that wraps a regular array. This has the benefit that interoperability is often easier, since most framework and tools accept accept pointers or 1D arrays, while few can handle a multidimensional array. Indexing can be done like:
public class MyMatrix<T>
{
public int Width { get; }
public T[] Data { get; }
public T this[int x, int y]
{
get => Data[y * Width + x];
set => Data[y * Width + x] = value;
}
}
There is also jagged arrays, but there is no guarantee that these will be "square", so they are probably not appropriate if you want a "matrix".
In all cases you will need to loop over the matrix and check each element if you want to do any kind of replacement. Some alternatives require separate loops for width/height, while some allow for a single loop.
I'm not sure if you want a matrix or an array.
Matrix would be like
string[,] matrix = new string[10, 10];
and array would be like
string[] array = new string[10];
You can access the array with array[i] and matrix with matrix[i, j]
You could also use
List<List<string>> matrix = new List<List<string>>(); which may be more convenient to work with and can also be access with indexers. For example
matrix[i][j] = "bob";
matrix[i].RemoveAt(j);
Given the problem you have submitted maybe just a List<string> would work for you.

Decreasing all values of a dictionary without loop. Or alternative storage possibility

I'm storing some data in a Math.net vector, as I have to do some calculations with it as a whole. This data comes with a time information when it was collected. So for example:
Initial = 5, Time 2 = 7, Time 3 = 8, Time 4 = 10
So when I store the data in a Vector it looks like this.
stateVectorData = [5,7,8,10]
Now sometimes I need to extract a single entry of the vector. But I don't have the index itself, but a time Information. So what I try is a dictionary with the information of the time and the index of the data in my stateVector.
Dictionary<int, int> stateDictionary = new Dictionary<int, int>(); //Dict(Time, index)
Everytime I get new data I add an entry to the dictionary(and of course to the stateVector). So at Time 2 I did:
stateDictionary.Add(2,1);
Now this works as long as I don't change my vector. Unfortunately I have to delete an entry in the vector when it gets too old. Assume time 2 is too old I delete the second entry and have a resulting vector of:
stateVector = [5,8,10]
Now my dictionary has the wrong index values stored.
I can think of two possible solutions how to solve this.
To loop through the dictionary and decrease every value (with key > 2) by 1.
What I think would be more elegant, is storing a reference to an vectorentry in the dictionary instead of the index.
So something like
Dictionary<int, ref int> stateDictionary =
new Dictionary<int, ref int>(); //Dict(Time, reference to vectorentry)
stateDictionary.Add(2, ref stateVector[1]);
Using something like this, I wouldn't care about deleting some entrys in the vector, as I still have the reference to the rest of the vectorentries. Now I know it's not possible to store a reference in C#.
So my question is, is there any alternative to looping through the whole dictionary? Or is there another solution without a dictionary I don't see at the moment?
Edit to answer juharr:
Time information doesn't always increase by one. Depends on some parallel running process and how long it takes. Probably increasing between 1 to 3. But also could be more.
There are some values in the vector which never get deleted. I tried to show this with the initial value of 5 which stays in the vector.
Edit 2:
Vector stores at least 5000 to 6000 elements. Maximum is not defined at the moment, as it is restricted by the elements I can handle in real time, so in my case I have about 0.01s to do my further calculations. This is why I search an effective way, so I can increase the number of elements in the vector (or increase the maximum "age" of my vectorentries).
I need the whole vector for calculation about 3 times the number I need to add a value.
I have to delete an entry with the lowest frequency. And finding a single value by its time key will be the most often case. Maybe 30 to 100 times a second.
I know this all sounds very undefined, but the frequency of finding and deleting part depends on an other process, which can vary a lot.
Though hope you can help me. Thanks so far.
Edit 3:
#Robinson
The exact number of times I need the whole vector also depends on the parallel process. Minimum would be two times every iteration (so twice in 0.01s), maximum at least 4 to 6 times every iteration.
Again, the size of the vector is what I want to maximize. So assumed to be very big.
Edit Solution:
First thanks to all, who helped me.
After experimenting a bit, I'm using the following construction.
I'm using a List, where I save the indexes in my state vector.
Additionally I use a Dictionary to assign my Time-key to the List Entry.
So when I delete something in the state vector, I loop only over the List, which seems to be much faster than looping the dictionary.
So it is:
stateVectorData = [5,7,8,10]
IndexList = [1,2,3];
stateDictionary = { Time 2, indexInList = 0; Time 3, indexInList = 1; Time 4, indexInList = 2 }
TimeKey->stateDictionary->indexInList -> IndexList -> indexInStateVector -> data
You can try this:
public class Vector
{
private List<int> _timeElements = new List<int>();
public Vector(int[] times)
{
Add(times);
}
public void Add(int time)
{
_timeElements.Add(time);
}
public void Add(int[] times)
{
_timeElements.AddRange(time);
}
public void Remove(int time)
{
_timeElements.Remove(time);
if (OnRemove != null)
OnRemove(this, time);
}
public List<int> Elements { get { return _timeElements; } }
public event Action<Vector, int> OnRemove;
}
public class Vectors
{
private Dictionary<int, List<Vector>> _timeIndex;
public Vectors(int maxTimeSize)
{
_timeIndex = new Dictionary<int, List<Vector>>(maxTimeSize);
for (var i = 0; i < maxTimeSize; i++)
_timeIndex.Add(i, new List<Vector>());
List = new List<Vector>();
}
public List<Vector> FindVectorsByTime(int time)
{
return _timeIndex[time];
}
public List<Vector> List { get; private set; }
public void Add(Vector vector)
{
List.Add(vector);
vector.Elements.ForEach(element => _timeIndex[element].Add(vector));
vector.OnRemove += OnRemove;
}
private void OnRemove(Vector vector, int time)
{
_timeIndex[time].Remove(vector);
}
}
To use:
var vectors = new Vectors(maxTimeSize: 6000);
var vector1 = new Vector(new[] { 5, 30, 8, 20 });
var vector2 = new Vector(new[] { 25, 5, 23, 11 });
vectors.Add(vector1);
vectors.Add(vector2);
var findsTwo = vectors.FindVectors(time: 5);
vector1.Remove(time: 5);
var findsOne = vectors.FindVectors(time: 5);
The same can be done for adding times, also the code is just for illustration purposes.

picking random name from text file in c# windows forms non repeatable

I was wondering how get on with this code, currently working on a tournament bracket system.
Currently I have created a comboBox that fetches all the lines from "log.txt" there are 16 lines in the txt file; then I created a assign button that is supposed to assign all the names into 16 textboxes called User1 --> User16, however the same name cant be repeated.
I looked at "Array of list" & "Array of string", but I seem to be stuck since I cant really figure out what to put in the code.
my random button looks like this at the moment:
private void assign_Click(object sender, EventArgs e)
{
int x;
Random rnd = new Random();
x = rnd.Next(0, 16);
User1.Text = comboBox2.Items[x].ToString();
x = rnd.Next(0, 16);
User2.Text = comboBox2.Items[x].ToString();
x = rnd.Next(0, 16);
User3.Text = comboBox2.Items[x].ToString();
x = rnd.Next(0, 16);
User4.Text = comboBox2.Items[x].ToString();
and so on untill i hit
x = rnd.Next(0, 16);
User16.Text = comboBox2.Items[x].ToString();
}
One of the simplest, but not necessarily most efficient, way to do this is to put all your strings into a List<string> and remove them randomly one-by-one. This would work a lot better if you put all your textboxes into a collection as well. For example, given a list of strings called myStrings and a collection of textboxes called myTextboxes, you could:
for (var i=0; i < myStrings.Count; i++)
{
var idx = rnd.Next(0, myStrings.Count);
myTextboxes[i].Text = myStrings[idx]; // Note: we are assuming the two collections have
// the same length
myStrings.RemoveAt(idx);
}
This is very easy to implement and very easy to get right, but it's not terribly efficient (for 16 items, it probably doesn't matter) because your collection is repeatedly resized. For a more efficient approach, first shuffle your strings using the Fisher-Yates shuffle and then just assign the first entry from your shuffled strings to the first textbox, the second to the second, and so on.
You could use a List, and after each assignment you could remove the assigned item from the list. This would prevent duplicates.
http://msdn.microsoft.com/en-us/library/cd666k3e(v=vs.110).aspx
How about removing each item after selecting it?
Try something like
comboBox1.Items.RemoveAt(x);
After adding it and each time your
x = rnd.Next(0, 16);
code will reduce to
x = rnd.Next(0, 15);
until it reaches zero.
A different approach would be after selecting one randomly loop through all the filled ones (or all in general for simpler code) and check if it is already selected. If already selected get a new one until it's different.
For that you could use an array of textboxes (store what you have in an array) and loop through them like so
for(int i=0;i<16;i++)
if(textBoxArray[i].Text==comboBox2.Items[x].toString()){
chosen=true;
}
But removing them from the combobox is much simpler and much faster as code. If you want them to still appear in your combobox you could simultaneously in a List, get your items from that List and remove it from there.
The user will not see anything.
To accomplish this, is fairly simple.
First, you know there are 16 items in total. You don't need to randomize the list but rather, randomize the index that you use to access the item of the list. This part you know.
In order to avoid repeating items, you need to keep a list of indexes that have already been used. Once you have determined an unused index, that's when you need to access your list.
Example:
class Sample
{
List<int> _usedIndexes;
public Sample()
{
_usedIndexes = new List<int>();
}
public int GetRandomIndex(int s, e)
{
Random rnd = new Random();
//Initialize with a random number
int x = rnd.Next(s, e);
//While the index exists in the list of used indexes, get another random number.
while(_usedIndexes.Exists(index => index == x))
{
x = rnd.Next(s, e);
}
//Add the number to the list of used indexes
_usedIndexes.Add(x);
return x;
}
}
Then you simply access the List of names you have with the index you have acquired as follows:
int unusedIndex = GetRandomIndex(0, 16);
User1.Text = comboBox2.Items[unusedIndex].ToString();

Storing mouse co-ordinates in session and adding to xml string (C# .NET MVC)

basically my aim is to use JQuery to post back an x & y mouse co-ordinate to my controller where the 2 values are added to an array/list which is then added to the session.
I want to iterate through a series of 60 clicks (and subsequently postbacks to the controller) before building an XML string with each co-ordinate in it.
Something along the lines of this:
<xml>
<click1>
<xpos>45</xpos>
<ypos>55</ypos>
</click1>
<click2>
<xpos>45</xpos>
<ypos>55</ypos>
</click2>
</xml>
I'm unsure as to how best to store the individual mouse clicks after each postback, and I thought perhaps a session and a multi-dimensional array/list would be good for this? I'm also a little confused as to how to convert the session back into a list and assemble the XML as required.
Could anyone point me in the right direction?
Many thanks!
Sykth.
I solved this by creating a Dictionary of type , with MouseCoordinates referring to a class which accepted 2 string values for xposition and yposition.
I then placed the Dictionary into a session, re-casting it as a Dict when I needed to add a new value to it.
Finally I looped through the Dictionary at the end of my cycle of clicks retrieving all the values.
I hope this code helps someone:
var coords = new Dictionary<int, MouseCoordinates>();
HttpContext.Session.Add("coords", coords);
// Accessing Dictionary From Session
var coords = (Dictionary<int, MouseCoordinates>)HttpContext.Session["coords"];
// Adding Values using a integer stage that's posted back to the controller
coords.Add(currentStage, new MouseCoordinates { xposition = xpos, yposition = ypos });
// Looping through the session at the end of the cycle
foreach (var ords in coords)
{
var qnode = ords.Key;
var xvalue = ords.Value.xposition;
var yvalue = ords.Value.yposition;
}

How do you initialize a 2 dimensional array when you do not know the size

I have a two dimensional array that I need to load data into. I know the width of the data (22 values) but I do not know the height (estimated around 4000 records, but variable).
I have it declared as follows:
float[,] _calibrationSet;
....
int calibrationRow = 0;
While (recordsToRead)
{
for (int i = 0; i < SensorCount; i++)
{
_calibrationSet[calibrationRow, i] = calibrationArrayView.ReadFloat();
}
calibrationRow++;
}
This causes a NullReferenceException, so when I try to initialize it like this:
_calibrationSet = new float[,];
I get an "Array creation must have array size or array initializer."
Thank you,
Keith
You can't use an array.
Or rather, you would need to pick a size, and if you ended up needing more then you would have to allocate a new, larger, array, copy the data from the old one into the new one, and continue on as before (until you exceed the size of the new one...)
Generally, you would go with one of the collection classes - ArrayList, List<>, LinkedList<>, etc. - which one depends a lot on what you're looking for; List will give you the closest thing to what i described initially, while LinkedList<> will avoid the problem of frequent re-allocations (at the cost of slower access and greater memory usage).
Example:
List<float[]> _calibrationSet = new List<float[]>();
// ...
while (recordsToRead)
{
float[] record = new float[SensorCount];
for (int i = 0; i < SensorCount; i++)
{
record[i] = calibrationArrayView.ReadFloat();
}
_calibrationSet.Add(record);
}
// access later: _calibrationSet[record][sensor]
Oh, and it's worth noting (as Grauenwolf did), that what i'm doing here doesn't give you the same memory structure as a single, multi-dimensional array would - under the hood, it's an array of references to other arrays that actually hold the data. This speeds up building the array a good deal by making reallocation cheaper, but can have an impact on access speed (and, of course, memory usage). Whether this is an issue for you depends a lot on what you'll be doing with the data after it's loaded... and whether there are two hundred records or two million records.
You can't create an array in .NET (as opposed to declaring a reference to it, which is what you did in your example) without specifying its dimensions, either explicitly, or implicitly by specifying a set of literal values when you initialize it. (e.g. int[,] array4 = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 } };)
You need to use a variable-size data structure first (a generic list of 22-element 1-d arrays would be the simplest) and then allocate your array and copy your data into it after your read is finished and you know how many rows you need.
I would just use a list, then convert that list into an array.
You will notice here that I used a jagged array (float[][]) instead of a square array (float [,]). Besides being the "standard" way of doing things, it should be much faster. When converting the data from a list to an array you only have to copy [calibrationRow] pointers. Using a square array, you would have to copy [calibrationRow] x [SensorCount] floats.
var tempCalibrationSet = new List<float[]>();
const int SensorCount = 22;
int calibrationRow = 0;
while (recordsToRead())
{
tempCalibrationSet[calibrationRow] = new float[SensorCount];
for (int i = 0; i < SensorCount; i++)
{
tempCalibrationSet[calibrationRow][i] = calibrationArrayView.ReadFloat();
} calibrationRow++;
}
float[][] _calibrationSet = tempCalibrationSet.ToArray();
I generally use the nicer collections for this sort of work (List, ArrayList etc.) and then (if really necessary) cast to T[,] when I'm done.
you would either need to preallocate the array to a Maximum size (float[999,22] ) , or use a different data structure.
i guess you could copy/resize on the fly.. (but i don't think you'd want to)
i think the List sounds reasonable.
You could also use a two-dimensional ArrayList (from System.Collections) -- you create an ArrayList, then put another ArrayList inside it. This will give you the dynamic resizing you need, but at the expense of a bit of overhead.

Categories

Resources