C# - Most efficient way to iterate through multiple arrays/list - c#

I have five arrays of varying lengths and I need to iterate through all of them generating all possible combinations of the contents. I'm currently using 5 nested for loops like so:
for (int a = 1; a < Array1.Length - 1; a++)
{
for (int b = 1; b < Array2.Length - 1; b++)
{
for (int c = 1; c < Array3.Length - 1; c++)
{
for (int d = 1; d < Array4.Length - 1; d++)
{
for (int e = 1; e < Array5.Length - 1; e++)
{
//do something
}
}
}
}
}
Due to the size of the arrays, I end up with more than 456 million iterations. I'm pretty new to programming in general, and C# specifically. I'm just curious if there is a more efficient way to accomplish this.
Thank you.

You go though that many iterations because there are that many combinations: this is called combinatorial explosion. You cannot do it more efficiently if you must go through all possible combinations.
You can code it with fewer lines of code or without hard-coding the number of arrays (five in your case) by using recursion. However, the number of iterations is not going to change, only the number of lines of code.
void processCombination(int[] combination) {
// combination[i] has the index of array #i
...
}
void combine(int p, int[] indexes, int[] sizes) {
if (p == indexes.Length) {
processCombination(indexes);
} else {
for (indexes[p] = 0 ; indexes[p] != sizes[p] ; indexes[p]++) {
combine(p+1, indexes, sizes);
}
}
}

Related

Bring multiple 2d arrays [][] on same length

i have a huge Problem when dealing with jagged arrays [][].
I wrote a program that interacts with lots of CSV-files. It will read them and then compare them. Now i have a problem if Array A has the dimension of 10 Rows and 10 Columns but Array B only has the dimension of 5 Rows and 5 Columns. I get the "out of range" on array B. This is only an example it gets even worse if i have a array which has different amount of Rows in each Column...
I tried checking for "null" but this doesnt work since i get the "out of range" once it tries to acess the field...
Now i have 2 theories to solve the problem:
A.)Check for "out of range" in Array B and if so fill Array A at the same field with a "0"
B.) Check if Array A and Array B has same dimension and if not fill the array with lesser amount with "0" so that it has the same amount
On both solutions i have absolutely no clue how to do this in C#... I am always getting the out of range...
What i currently do for 1 array is:
for (int b = CSV_Statistiken.Length - 1; b >= 0; b--)
{
for (int a = 0; a < CSV_Statistiken[b].Length; a++)
{
CSV_Statistiken[b][a] = 1;
}
}
so i get the dimension of the array and iterate through it, setting every value to 1. But how do i deal with my problem with 2 arrays?
I researched a bit but couldnt find any solution to this =/
Thanks in advance
Edit: What i am trying to do for examlple:
for (int i = 0; i < number; i++) //runs through every File existing
{
NextFile = fold.Filepath + "\\" + files[i].ToString();
file = new FileInfo(#NextFile);
max_Rows = 0;
max_Col = 0;
CSV_temp = ReadCSV(file, ref max_Rows, ref max_Col); // reads the next file to an arraay [][] and saves the size of this array in max_col/ max_rows
MAX_Col_Total = GetHighestValues(ref MAX_Col_Total, max_Col);
MAX_Rows_Total = GetHighestValues(ref MAX_Rows_Total, max_Rows);
for (int j = 0; j < MAX_Col_Total; j++) //runs thrugh the max amount of cols found
{
for (int k = MAX_Rows_Total - 1; k >= 0; k--) //runs through the max mount of rows found
{
if (CSV_temp.GetLength(0) >= j && CSV_temp.GetLength(1) >= k)//Checks if Field exists -> does NOT work!
{
if (CSV_temp[k][j] > (Threshhold))) //
{
do something
}
}
else
{
// Field doesnt exists -> do something else
}
}
}
}
You can check Lengths of two arrays in for loops:
for (int a = 0; a < array1.Length && a < array2.Length; a++)
{
for (int b = 0; b < array1[a].Length && b < array2[a].Length; b++)
{
//compare
}
}
Now your loops never go outside of any array index and you won't get IndexOutOfRangeException.
EDIT:
var biggestLength1 = Math.Max(array1.Length, array2.Length);
for (int a = 0; a < biggestLength1; a++)
{
var biggestLength2 = 0;
if (array1.Length > a && array2.Length > a)
{
biggestLength2 = Math.Max(array1[a].Length, array2[a].Length);
}
else
{
biggestLength2 = array1.Length > a ? array1.Length : array2.Length;
}
for (int b = 0; b < biggestLength2; b++)
{
if (a < array1.Length &&
a < array2.Length &&
b < array1[a].Length &&
b < array2[a].Length)
{
// every array has enough elements count
// you can do operations with both arrays
}
else
{
// some array is bigger
}
}
}

Increment groups of numbers in c# .net

In the scenario where you have two groups of numbers, each containing the numbers 1 to 10, how would you go about incrementing each number until it hits its upper limit?
For example, to procude the numbers as follows:
1.1
1.2
1.3
...
1.9
1.10
2.1
2.2
2.3
...
2.9
2.10
etc...
My effort is pretty abysmal so far - I started with for loops and couldnt get a decent result, moved onto a while loop and still havent got a working solution, but here's what I have so far.
class Program
{
static void Main()
{
int group01 = 1;
int group01Max = 10;
int group02 = 2;
int group02Max = 10;
while (group01 < group01Max)
{
while (group02 < group02Max)
{
Console.WriteLine(string.Format("{0}.{1}", group01, group02));
}
}
}
}
I'm not entirely sure if this is what you're asking, but do you mean something like this?
a = 10
b = 10
for(int i = 0; i < a; i++){
string tmp = i.toString();
for(int j = 0; j < b; j++){
tmp += "." + j.toString();
}
Console.WriteLine(tmp);
}
edit: using $"" notation would simplify this as done in the answer below
a = 10
b = 10
for(int i = 0; i < a; i++){;
for(int j = 0; j < b; j++){
Console.WriteLine($"{i}.{j}");
}
}
It can be easily done by nesting one loop in another loop.
foreach(var firstIndex in firstGroup)
{
foreach(var secondIndex in secondGroup)
{
Console.WriteLine($"{firstIndex}.{secondIndex}");
}
}
Enumerable.Range(1, 10).Select(n1 => Enumerable.Range(1, 10).Select(n2 => (n1, n2)))
Or if you want the special formatting,
Enumerable.Range(1, 10).SelectMany(n1 => Enumerable.Range(1, 10).Select(n2 => $"{n1}.{n2}"))

Cannon's algorithm of matrix multiplication

I try to implement the Cannon's algorithm of matrix multiplication.
I read description on the wikipedia that provides next pseudocode:
row i of matrix a is circularly shifted by i elements to the left.
col j of matrix b is circularly shifted by j elements up.
Repeat n times:
p[i][j] multiplies its two entries and adds to running total.
circular shift each row of a 1 element left
circular shift each col of b 1 element up
and I implemented it on the C# next way:
public static void ShiftLeft(int[][] matrix, int i, int count)
{
int ind = 0;
while (ind < count)
{
int temp = matrix[i][0];
int indl = matrix[i].Length - 1;
for (int j = 0; j < indl; j++)
matrix[i][j] = matrix[i][j + 1];
matrix[i][indl] = temp;
ind++;
}
}
public static void ShiftUp(int[][] matrix, int j, int count)
{
int ind = 0;
while (ind < count)
{
int temp = matrix[0][j];
int indl = matrix.Length - 1;
for (int i = 0; i < indl; i++)
matrix[i][j] = matrix[i + 1][j];
matrix[indl][j] = temp;
ind++;
}
}
public static int[][] Cannon(int[][] A, int[][] B)
{
int[][] C = new int[A.Length][];
for (int i = 0; i < C.Length; i++)
C[i] = new int[A.Length];
for (int i = 0; i < A.Length; i++)
ShiftLeft(A, i, i);
for (int i = 0; i < B.Length; i++)
ShiftUp(B, i, i);
for (int k = 0; k < A.Length; k++)
{
for (int i = 0; i < A.Length; i++)
{
for (int j = 0; j < B.Length; j++)
{
var m = (i + j + k) % A.Length;
C[i][j] += A[i][m] * B[m][j];
ShiftLeft(A, i, 1);
ShiftUp(B, j, 1);
}
}
};
return C;
}
this code return correct result, but do it very slowly. Much slowly even than naive algorithm of matrix multiplication.
For matrix 200x200 I got that result:
00:00:00.0490432 //naive algorithm
00:00:07.1397479 //Cannon's algorithm
What I am doing wrong?
Edit
Thanks SergeySlepov, it was bad attempt to do it parallel. When I back to sequential implementation I got next result:
Count Naive Cannon's
200 00:00:00.0492098 00:00:08.0465076
250 00:00:00.0908136 00:00:22.3891375
300 00:00:00.1477764 00:00:58.0640621
350 00:00:00.2639114 00:01:51.5545524
400 00:00:00.4323984 00:04:50.7260942
okay, it's not a parallel implementation, but how can I do it correctly?
Cannon's algorithm was built for a 'Distributed Memory Machine' (a grid of processors, each with its own memory). This is very different to the hardware you're running it on (a few processors with shared memory) and that is why you're not seeing any increase in performance.
The 'circular shifts' in the pseudocode that you quoted actually mimic data transfers between processors. After the initial matrix 'skewing', each processor in the grid keeps track of three numbers (a, b and c) and executes pseudocode similar to this:
c += a * b;
pass 'a' to the processor to your left (wrapping around)
pass 'b' to the processor to 'above' you (wrapping around)
wait for the next iteration of k
We could mimic this behaviour on a PC using NxN threads but the overhead of context switching (or spawning Tasks) would kill all the joy. To make the most of a PC's 4 (or so) CPUs we could make the loop over i parallel. The loop over k needs to be sequential (unlike your solution), otherwise you might face racing conditions as each iteration of k modifies the matrices A, B and C. In a 'distributed memory machine' race conditions are not a problem as processors do not share any memory.

Ranking with tiebreakers

How do I go about ranking a list based on one criteria, and then separating ties (of which there are likely to be a lot) based on another?
My (working) attempt to rank drivers based on their points totals.
for (int j = 0; j < career.NumberOfDrivers; j++)
{
int rank = 1;
for (int i = 0; i < career.NumberOfDrivers; i++)
{
if (career.driver[j].championshipPoints < career.driver[i].championshipPoints)
{
rank += 1;
}
}
career.driver[j].championshipRank = rank;
}
Presumably I then want to cycle through afterwards checking for ties - the problem is there are definitely going to be situations when I have several drivers tied on 0.
How do I go about simply breaking these tiebreakers alphabetically (ie based on first letter of driver's names)?
EDIT - my solution if its of interest. Pretty nasty hack in some respects but does the job.
List<Driver> tempDriver = new List<Driver>();
for (int i = 0; i < career.driver.Count; i++)
{
tempDriver.Add(career.driver[i]);
}
tempDriver.Sort(
delegate(Driver d1, Driver d2)
{
if (d1.championshipPoints == d2.championshipPoints)
{
return d1.Name.CompareTo(d2.Name);
}
return d1.championshipPoints.CompareTo(d2.championshipPoints);
}
);
for (int i = 0; i < career.NumberOfDrivers; i++)
{
for (int j = 0; j < career.NumberOfDrivers; j++)
{
if (career.driver[i].Name == tempDriver[j].Name)
{
career.driver[i].championshipRank = j + 1;
}
}
}
You can use Sort() on your drivers List, using a delegate.
If drivers have same points number, return the comparison result of their names.
Else return the comparison or their points
driversList.Sort(
delegate(Driver d1, Driver d2)
{
if (d1.championshipPoints == d2.championshipPoints)
{
return d1.name.CompareTo(d2.name);
}
return d1.championshipPoints.CompareTo(d2.championshipPoints);
}
);
Then the ranking of a driver is simply its index in the sorted list.
Edit:
This solution has n*log(n) complexity (the OP first attempt is O(n^2) )

How to code for dynamic for-loop levels?

My problem is like this:
I have several lists need to be permuted, but the list numbers are unknowable. And every element numbers in every list are also unknowable. Sicne I would like to traverse all list element combination, like 1) pick A from list 1, A from list 2, A from list 3; 2) ick A from list 1, A from list 2, B from list 3 ... for ALL permutation.
I use nested for-loop to traverse, like if I have two lists, then:
for (int i = 0; i < list[0].EnergyParameters.ListEnergyLevelCandidates.Count; i++)
{
for (int j = 0; j < list[1].EnergyParameters.ListEnergyLevelCandidates.Count; j++)
{
// Do sth
}
}
If I have three lists, then:
for (int i = 0; i < list[0].EnergyParameters.ListEnergyLevelCandidates.Count; i++)
{
for (int j = 0; j < list[1].EnergyParameters.ListEnergyLevelCandidates.Count; j++)
{
for (int k = 0; k < list[2].EnergyParameters.ListEnergyLevelCandidates.Count; k++)
{
// Do sth
}
}
}
Because the list numbers are unknowable, so the nest numbers are unknowable, which means, I don't know how many levels of for-loop needs to be written.
Under this kind of circumstance, how can I write code for dynamic for-loop levels? I don't want to write 10 loops for 10 lists.
In case you do not know how many lists there are, you do not write nested loops: instead, you write recursion. At each level of the invocation you loop a single list, like this:
void AllCombos(List<string>[] lists, int level, string[] current) {
if (level == lists.Length) {
// Do somthing; items of current[] contain elements of the combination
} else {
foreach (var s in lists[level]) {
current[level] = s;
AllCombos(lists, level+1, current);
}
}
}
Call AllCombos as follows:
var lists = new List<string>[10];
for (int i = 0 ; i != 10 ; i++) {
lists[i] = PopulateMyList(i);
}
string[] current = new string[lists.Length];
AllCombos(lists, 0, current);

Categories