Multi-Dimensional Data Structures in C# - c#

How do you create a multi-dimensional data structure in C#?
In my mind it works like so:
List<List<int>> results = new List<List<int>>();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
results[i][j] = 0;
}
}
This doesn't work (it throws an ArgumentOutOfRangeException). Is there a multi-dimensional structure in C# that allows me to access members through their indexes?

The problem here is that List doesn't automatically create elements. To initialise a List<List<T>> you need something like this:
List<List<int>> results = new List<List<int>>();
for (int i = 0; i < 10; i++)
{
results.Add(new List<int>());
for (int j = 0; j < 10; j++)
{
results[i].Add(0);
}
}
Note that setting Capacity is not sufficient, you need to call Add the number of times you need. Alternatively, you can simplify things by using Linq's Enumerable class:
List<List<int>> results = new List<List<int>>();
for (int i = 0; i < 10; i++)
{
results.Add(new List<int>());
results[i].AddRange(Enumerable.Repeat(0, 10));
}
Again, note that Enumerable.Repeat(new List<int>(), 10) will not work, since it will add 10 references to the same list.
Another approach using Linq to the extreme:
List<List<int>> results = Enumerable.Repeat(0, 10)
.Select(i => Enumerable.Repeat(0, 10).ToList())
.ToList();
(The unused parameter i is necessary to ensure that you don't reference the same list ten times as discussed above.)
Finally, to access elements, you can use exactly the notation you used before. Once the elements have been added, they can be read or modified as shown:
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
results[i][j] = 2;
int x = results[i][j];
}
}

If you know the dimensions of your structure in advance, and you do not plan to add or remove elements, then a 2D array sounds like your thing:
int[,] n = new int[10, 20];
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
n[i, j] = ...
};
};

You have to create the lists and initialize them with zeros before you can't start indexing into them.
List<List<int>> results = new List<List<int>>();
for (int i = 0; i < 10; i++)
{
results.Add(new List<int>(Enumerable.Repeat(0, 10)));
}

You have to actually 1) create each of the inner lists, and 2) set them to that size.
var Results = Enumerable.Range(0, 10).Select(i => Enumerable.Repeat(0, 10).ToList()).ToList();
I'm a bit of a Linq addict, though.

You could use a datatable and add columns and rows? You would then be able to reference them by name or index.

Related

Do you always have to start at the index zero when writing a 2D list?

I want to fill in a 2Dlist, but start at the third position [2]. Is this somehow possible?
A short code for understanding what i mean:
List<List<string>> List2D = new List<List<string>>();
for (int i = 0; i < 5; i++)
{
List2D[2].Add("i")
}
I get the following error:
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
EDIT: Any idea how to fill in a 4D list?
List<List<List<List<string>>>> List4D = new List<List<List<List<string>>>>();
for (int i = 0; i < List1.Count; i++)
{
List<List<List<string>>> List3D = new List<List<List<string>>>();
for (int j = 0; j < List2.Count; j++)
{
List<List<string>> List2D = new List<List<string>>();
for (int k = 0; k < List3.Count; k++)
{
List<string> Lijst1D = new List<string>();
List2D.Add(Lijst1D);
}
List3D.Add(List2D);
}
List4D.Add(List3D);
}
So later I can call: List4D[2][3][0].Add("test");
Since you just created your List2D and not added any nested list into it, you can't access its third element (there is nothing there).
You have to add some items first:
List<List<string>> List2D = new List<List<string>>();
List2D.Add(new List<string>());
List2D.Add(new List<string>());
List2D.Add(new List<string>());
for (int i=0; i<5; i++)
{
List2D[2].Add("i")
}
Update
Well, core idea of filling that list remains the same: if you want to access List4D[2][3][0] - first you need to fill all of lists in "path".
You can do it something like this:
List<List<List<List<string>>>> List4D = new List<List<List<List<string>>>>();
int i1 = 2, i2 = 3, i3 = 0;
for (int i = 0; i <= Math.Max(i1, 1); i++)
List4D.Add(new List<List<List<string>>>());
for (int i = 0; i <= Math.Max(i2, 1); i++)
List4D[i1].Add(new List<List<string>>());
for (int i = 0; i <= Math.Max(i3, 1); i++)
List4D[i1][i2].Add(new List<string>());
List4D[i1][i2][i3].Add("test");
Frankly, idea of 4D list looks a little bit "syntetic". In real application probably it is not the best data structure because of clumsy addressing.

Add Multidimensional Array To List

I have a multidimensional double array with any number of rows and columns:
var values = new double[rows, columns];
I also have a list of double arrays:
var doubleList = new List<double[]>();
Now, I would like to add each column in the multidimensional array to the list. How do I do that? I wrote this to illustrate what I want, but it does not work as I am violation the syntax.
for (int i = 0; i < columns; i++)
{
doubleList.Add(values[:,i];
}
var values = new double[rows, columns];
var doubleList = new List<double[]>();
for (int i = 0; i < columns; i++)
{
var tmpArray = new double[rows];
for (int j = 0; j < rows; i++)
{
tmpArray[j] = values[j, i];
}
doubleList.Add(tmpArray);
}
You will need to create a new array for each column and copy each value to it.
Either with a simple for-loop (like the other answers show) or with LINQ:
for (int i = 0; i < columns; i++)
{
double[] column = Enumerable.Range(0, rows)
.Select(row => values[row, i]).ToArray();
doubleList.Add(column);
}
With the approach you were taking:
for(int i = 0; i != columns; ++i)
{
var arr = new double[rows];
for(var j = 0; j != rows; ++j)
arr[j] = values[j, i];
doubleList.Add(arr);
}
Build up the each array, per row, then add it.
Another approach would be:
var doubleList = Enumerable.Range(0, columns).Select(
i => Enumerable.Range(0, rows).Select(
j => values[j, i]).ToArray()
).ToList()
Which some would consider more expressive in defining what is taken (values[j, i] for a sequence of i inner sequence of j) and what is done with them (put each inner result into an array and the result of that into a list).

filling multidimensional array with unique numbers in C#

I'm trying to write a code that will fill array with unique numbers.
I could write the code separately for 1, 2 and 3 dimensional arrays but number of for cycles grow to "infinity".
this is the code for 2D array:
static void fillArray(int[,] array)
{
Random rand = new Random();
for (int i = 0; i < array.GetLength(0); i++)
{
for (int j = 0; j < array.GetLength(1); j++)
{
array[i, j] = rand.Next(1, 100);
for (int k = 0; k < j; k++)
if (array[i, k] == array[i, j])
j--;
}
}
print_info(array);
}
Is it possible to do something like this for n-dimensional arrays?
My approach is to start with a 1-d array of unique numbers, which you can shuffle, and then slot into appropriate places in your real array.
Here is the main function:
private static void Initialize(Array array)
{
var rank = array.Rank;
var dimensionLengths = new List<int>();
var totalSize = 1;
int[] arrayIndices = new int[rank];
for (var dimension = 0; dimension < rank; dimension++)
{
var upperBound = array.GetLength(dimension);
dimensionLengths.Add(upperBound);
totalSize *= upperBound;
}
var singleArray = new int[totalSize];
for (int i = 0; i < totalSize; i++) singleArray[i] = i;
singleArray = Shuffle(singleArray);
for (var i = 0; i < singleArray.Length; i++)
{
var remainingIndex = i;
for (var dimension = array.Rank - 1; dimension >= 0; dimension--)
{
arrayIndices[dimension] = remainingIndex%dimensionLengths[dimension];
remainingIndex /= dimensionLengths[dimension];
}
// Now, set the appropriate cell in your real array:
array.SetValue(singleArray[i], arrayIndices);
}
}
The key in this example is the array.SetValue(value, params int[] indices) function. By building up the correct list of indices, you can use this function to set an arbitrary cell in your array.
Here is the Shuffle function:
private static int[] Shuffle(int[] singleArray)
{
var random = new Random();
for (int i = singleArray.Length; i > 1; i--)
{
// Pick random element to swap.
int j = random.Next(i); // 0 <= j <= i-1
// Swap.
int tmp = singleArray[j];
singleArray[j] = singleArray[i - 1];
singleArray[i - 1] = tmp;
}
return singleArray;
}
And finally a demonstration of it in use:
var array1 = new int[2,3,5];
Initialize(array1);
var array2 = new int[2,2,3,4];
Initialize(array2);
My strategy assigns sequential numbers to the original 1-d array to ensure uniqueness, but you can adopt a different strategy for this as you see fit.
You can use Rank property to get the total number of dimentions in your array
To insert use SetValue method
In the first two for loops you are analysing the array properly (i and j go from the start to the end of the corresponding dimension). The problem comes in the most internal part where you introduce a "correction" which actually provokes an endless loop for j.
First iteration:
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
Second iteration
- First loop: i = 0;
- Second loop: j = 0;
- Third loop: j = -1
. etc., etc.
(I start my analysis in the moment when the internal loop is used for the first time. Also bear in mind that the exact behaviour cannot be predicted as far as random numbers are involved. But the idea is that you are making the j counter back over and over by following an arbitrary rule).
What you want to accomplish exactly? What is this last correction (the one provoking the endless loop) meant to do?
If the only thing you intend to do is checking the previously stored values, you have to rely on a different variable (j2, for example) which will not affect any of the loops above:
int j2 = j;
for (int k = 0; k < j2; k++)
if (array[i, k] == array[i, j2])
j2--;

Find intersection group of sorted integer arrays

Let's we have some integer short sorted arrays and we need to find intersection equal or more then predefined constant.
Here is code and it demonstrates what i want to do better then i can explain it in words.
The problem is SPEED. My code is working very slow. It takes about 15 sec on 2000 elements array(on my slow machine). Ofcourse i can implement my own intersection method and parallize code but it give a very limited improvement. Execution time growing as N^2 or something and already for 500k arrays it takes a very very long time. So how can i rewrite algorithm for better perfomance? I am not limited c# language maybe CPU or GPU has good special instructions for such job.
Example:
Input:
1,3,7,8
2,3,8,10
3,10,11,12,13,14
minSupport = 1
Output:
1 and 2: 2, 8
1 and 3: 3
2 and 3: 3, 10
var minSupport = 2;
var random = new Random(DateTime.Now.Millisecond);
// Numbers is each array are unique
var sortedArrays = Enumerable.Range(0,2000)
.Select(x => Enumerable.Range(0,30).Select(t => random.Next(1000)).Distinct()
.ToList()).ToList();
var result = new List<int[]>();
var resultIntersection = new List<List<int>>();
foreach (var array in sortedArrays)
{
array.Sort();
}
var sw = Stopwatch.StartNew();
//****MAIN PART*****//
for (int i = 0; i < sortedArrays.Count-1; i++)
{
for (int j = i+1; j < sortedArrays.Count; j++)
{
var intersect = sortedArrays[i].Intersect(sortedArrays[j]).ToList();
if(intersect.Count()>=minSupport)
{
result.Add( new []{i,j});
resultIntersection.Add(intersect);
}
}
}
//*****************//
sw.Stop();
Console.WriteLine(sw.Elapsed);
EDIT:
Now it takes about 9 sec vs 15 sec with old algorithm on 2000 elements. Well...ofcourse it is not fast enough.
//****MAIN PART*****//
// This number(max value which array can contains) is known
var maxValue = 1000;
var reverseIndexDict = new Dictionary<int,List<int>>();
for (int i = 0; i < maxValue; i++)
{
reverseIndexDict[i] = new List<int>();
}
for (int i = 0; i < sortedArrays.Count; i++)
{
for (int j = 0; j < sortedArrays[i].Count; j++)
{
reverseIndexDict[sortedArrays[i][j]].Add(i);
}
}
var tempArr = new List<int>();
for (int i = 0; i < sortedArrays.Count; i++)
{
tempArr.Clear();
for (int j = 0; j < sortedArrays[i].Count; j++)
{
tempArr.AddRange(reverseIndexDict[j]);
}
result.AddRange(tempArr.GroupBy(x => x).Where(x => x.Count()>=minSupport).Select(x => new[]{i,x.Key}).ToList());
}
result = result.Where(x => x[0]!=x[1]).ToList();
for (int i = 0; i < result.Count; i++)
{
resultIntersection.Add(sortedArrays[result[i][0]].Intersect(sortedArrays[result[i][1]]).ToList());
}
//*****************//
EDIT:
Some improvent.
//****MAIN PART*****//
// This number(max value which array can contains) is known
var maxValue = 1000;
var reverseIndexDict = new List<int>[maxValue];
for (int i = 0; i < maxValue; i++)
{
reverseIndexDict[i] = new List<int>();
}
for (int i = 0; i < sortedArrays.Count; i++)
{
for (int j = 0; j < sortedArrays[i].Count; j++)
{
reverseIndexDict[sortedArrays[i][j]].Add(i);
}
}
for (int i = 0; i < sortedArrays.Count; i++)
{
var tempArr = new Dictionary<int, List<int>>();
for (int j = 0; j < sortedArrays[i].Count; j++)
{
var sortedArraysij = sortedArrays[i][j];
for (int k = 0; k < reverseIndexDict[sortedArraysij].Count; k++)
{
if(!tempArr.ContainsKey(reverseIndexDict[sortedArraysij][k]))
{
tempArr[reverseIndexDict[sortedArraysij][k]] = new[]{sortedArraysij}.ToList();
}
else
{
tempArr[reverseIndexDict[sortedArraysij][k]].Add(sortedArrays[i][j]);
}
}
}
for (int j = 0; j < reverseIndexDict.Length; j++)
{
if(reverseIndexDict[j].Count>=minSupport)
{
result.Add(new[]{i,j});
resultIntersection.Add(reverseIndexDict[j]);
}
}
}
// and here we are filtering collections
//*****************//
There are two solutions:
Let us suppose you have 3 sorted arrays and you have to find the intersection between them. Traverse the first array and run a binary search on the rest of the two arrays for the element in first array. If the respective binary search on two list gave positive, then increment the counter of intersection.
result = List
for element in Array1:
status1 = binarySearch(element, Array2)
status2 = binarySearch(element, Array2)
status = status & status
if status == True:
count++
if count == MAX_INTERSECTION:
result.append(element)
break
Time Complexity : N * M * Log(N),
where,
N = Number of element in the array
M = Number of arrays
This solution works only if the number in the arrays are positive integers. Calculate the maximum and the minimum number out of the total elements in all the sorted arrays. As it is sorted, we can determine it by surveying the start and end element of the sorted arrays given. Let the greatest number be max and the lowest number be min. Create an array of size max - min and fill it with zero. Let us suppose you have 3 Arrays, now start traversing the first array and and go to the respective index and increment the value in the previously created array. As mentioned below:
element is 5 in Array 1, the New_array[5]+=1
Traverse all the three sorted list and perform the operation mentioned above. At the end traverse the new_array and look for value equal to 3, these indexes are the intersection result.
Time Complexity : O(N) + O(N) + .. = O(N)
Space Complexity : O(maximum_element - minimum_element)
where,
N = number of elements in the array.

Delete row of 2D string array in C#

I am making a program that stores data in a 2D array. I would like to be able to delete rows from this array. I cannot figure out why this code doesn't work:
for (int n = index; n < a.GetUpperBound(1); ++n)
{
for (int i = 0; i < a.GetUpperBound(0); ++i)
{
a[i, n] = a[i, n + 1];
}
}
Could someone please help me out? I would like it to delete a single row and shuffle all the rows below it up one place. Thankyou!
you need to create a new array if you want to delete an item
try something like this
var arrayUpdated = new string[a.GetUpperBound(1)][a.GetUpperBound(0)-1];
for (int n = index; n < a.GetUpperBound(1); n++)
{
for (int i = 0; i < a.GetUpperBound(0); i++)
{
arrayUpdated [i, n] = a[i, 1];
}
}
The nested for loop method here works well: https://stackoverflow.com/a/8000574
Here's a method that converts the outer loop of the [,] array method above to use linq. Using linq here is only recommended if you are also doing other things with linq during the traversal.
public T[,] RemoveRow<T>(T[,] array2d, int rowToRemove)
{
var resultAsList = Enumerable
.Range(0, array2d.GetLength(0)) // select all the rows available
.Where(i => i != rowToRemove) // except for the one we don't want
.Select(i => // select the results as a string[]
{
T[] row = new T[array2d.GetLength(1)];
for (int column = 0; column < array2d.GetLength(1); column++)
{
row[column] = array2d[i, column];
}
return row;
}).ToList();
// convert List<string[]> to string[,].
return CreateRectangularArray(resultAsList); // CreateRectangularArray() can be copied from https://stackoverflow.com/a/9775057
}
used Enumerable.Range to iterate all rows as done in https://stackoverflow.com/a/18673845
Shouldn't ++i be i++? ++i increments before matrix operation is performed(ie pre-increment)

Categories