How to code for dynamic for-loop levels? - c#

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

Related

Searching two lists with nested loop

I'm trying to find an apartment number which is not already taken. So list<> is a list with already taken apartments and all<> is a list of all the apartments. so I try to iterate through them to find an apartment that is not already taken.
This does not work:
list<> // 4 indexes
all<> // 25 indexes
for (int i = 0;i < all.Count; i++)
{
for (int j = 0; j < list.Count; j++)
{
if (all[i].apartmentNr != list[j].apartmentNr)
{
apartmentNr = all[i].apartmentNr;
}
}
}
The problem is that you don't check all the list items so apartmentNr is set on first mismatch, but it's possibly taken on next list item. Thus you need to check all list items, before you can make a conclusion that it's free:
list<> // 4 indexes
all<> // 25 indexes
for (int i = 0;i < all.Count; i++)
{
bool taken = false;
for (int j = 0; j < list.Count; j++)
{
if (all[i].apartmentNr == list[j].apartmentNr)
{
taken = true;
break; // no need to check the rest
}
}
if (!taken) {
apartmentNr = all[i].apartmentNr;
break; // found first free
}
}
using System.Linq;
//availableApartments will contain all available apartments
var availableApartments = all.Except(list)
// Will get you the first item.
var freeApartment = availableApartments.FirstOrDefault()
Reference - Enumerable.Except

Iterate every combination of two elements in HashSet

How could I iterate through each combination of two elements in a HashSet once?
foreach (var elt1 in hashSet) {
foreach (var elt2 in hashSet) {
...
}
}
This would iterate the combinations of two but would iterate each combination TWICE. I'd like to do it once.
I think it's easy to do in Python. Is there any way to do it in C#?
Sample:
input hashSet: { 1, 2, 3, 4 }
iterate through: (1,2), (1,3), (1,4), (2,3), (2,4), (3,4)
There is no built-in method to do this in C#. Since HashSet<T> is not indexed *, you cannot do it with two loops either.
If this is a one-time deal, the simplest solution is to make two nested loops on the results of ToList() or ToArray(), like this:
var items = hashSet.ToList();
for (var i = 0 ; i != items.Count ; i++) {
var a = items[i];
for (var j = i+1 ; j != items.Count ; j++) {
var b = items[i];
}
}
If you are looking for something reusable, make an extension method on IEnumerable<T> that produces all pairs:
static IEnumerable<Tuple<T,T>> MakeAllPairs<T>(this IEnumerable<T> data) {
var items = data.ToList();
for (var i = 0 ; i != items.Count ; i++) {
var a = items[i];
for (var j = i+1 ; j != items.Count ; j++) {
var b = items[i];
yield return Tuple.Create(a, b);
}
}
}
Now you can iterate your pairs in a single loop:
foreach (var pair in hashSet.MakeAllPairs()) {
Console.WriteLine("{0} {1}", pair.Item1, pair.Item2);
}
* Technically, you could use ElementAt<T>(int) extension from Enumerable, but that would be very slow on large sets.
I misread the question originally. This is a new answer
This is what you want (if working index-based is an option). Explanation is below
string[] myArray = GetArray();
for (int i = 0; i < myArray.Length - 1; i++)
{
var element1 = myArray[i];
for(int j = i + 1; j < myArray.Length; j++)
{
var element2 = myArray[j];
Console.WriteLine("{0} {1}", element1, element2);
}
}
Explanation: Assume the following array:
Apple, Banana, Coconut, Zucchini
When i = 0 (Apple), j will be 1 (Banana), then 2 (Coconut), then 3 (Zucchini)
When i = 1 (Banana), j will be 2 (Coconut), then 3 (Zucchini).
And so on...
Basically, you are making sure element j is always ahead of element i. This means you've effectively removed half of the possibilities (where j would be before i), which is what you wanted.
Note: if you want to use sets of equal elements (Apple + Apple), the second for loop needs to change to:
for(int j = i; j < myArray.Length; j++) //notice j = i instead of i + 1
You can work with indexes directly on the HashSet.
Try this:
int int1, int2;
HashSet<int> hs = new HashSet<int>();
hs.Add(1);
hs.Add(2);
hs.Add(3);
for (int i = 0; i < hs.Count-1; i++) {
int1 = hs.ElementAt<int>(i);
for (int j = i + 1; j < hs.Count; j++)
{
int2 = hs.ElementAt<int>(j);
}
}
To return all permutations (viz (1,2) and (2,1)), you can cross join the set with itself using SelectMany:
var hashSet = new HashSet<int>{1,2,3,4,5,6,7,8};
foreach (var elt in hashSet.SelectMany(
x => hashSet.Select(y => new Tuple<int, int>(x, y))))
{
Debug.WriteLine("{0}-{1}", elt.Item1, elt.Item2);
}
Edit: If you just want the unique combinations (viz (1,2) but not (2,1)) then just add a filter only larger values during the cross join:
var hashSet = new HashSet<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
foreach (var elt in hashSet.SelectMany(
x => hashSet.Where(y => y >= x)
.Select(y => new Tuple<int, int>(x, y))))
{
Debug.WriteLine("{0}-{1}", elt.Item1, elt.Item2);
}

Resetting lists in c#

Following are two pieces of code I used to compute power sets of elements in a list
code 1)
public static List<List<int>> getCpower(List<int> list)
{
var result = new List<List<int>>();
for (int i = 0; i < (1 << list.Count); i++)
{
var sublist = new List<int>();
for (int j = 0; j < list.Count; j++)
{ if ((i & (1 << j)) != 0)
{ sublist.Add(list[j]);
}
}
result.Add(sublist);
}
return result;
}
code 2)
public static List<List<int>> getCpower(List<int> list)
{
var result = new List<List<int>>();var sublist = new List<int>();
for (int i = 0; i < (1 << list.Count); i++)
{
sublist.Clear();sublist.TrimExcess();
for (int j = 0; j < list.Count; j++)
{ if ((i & (1 << j)) != 0)
{ sublist.Add(list[j]);
}
}
result.Add(sublist);
}
return result;
}
The first code used a new statement and if i try to find out powersets of list with count 30 then OutOfMemoryException arises.So to save memory i used Clear() and TrimExcess() to get the list as if it were initialized using a new statement in code2. But these two codes return different results. I do not get why is this happening. Please help.
Are the two following two pieces not doing the same thing
for(....)
{
var sublist = new List<int>();
for(......)
{
//some code
}
}
and
var sublist = new List<int>();
for(.....)
{
sublist.Clear();sublist.TrimExcess();
for(.... )
{
//some code
}
}
In your second code, you only have a single nested list - you're adding several references referring to the same sublist, which is pointless.
Have you considered that maybe the reason you're running out of space with your first code is because you're fundamentally trying to hold too much data in memory at a time?
You could consider returning an IEnumerable<List<int>> like this:
public static IEnumerable<List<int>> getCpower(List<int> list)
{
for (int i = 0; i < (1 << list.Count); i++)
{
var sublist = new List<int>();
for (int j = 0; j < list.Count; j++)
{ if ((i & (1 << j)) != 0)
{
sublist.Add(list[j]);
}
}
yield return sublist;
}
}
This will now be lazily evaluated - so you could iterate over the top-level sequence, but unless the lists are retained by the caller, you'll only have a single list in memory at a time.
In the second piece of code you are clearing the list of results. This alters the outcome of your algorithm. You are throwing away your results because you are reusing the same list instance for all iterations.
In the second code example, you only ever have a single sublist instance. That same instance is cleared and added to the list again every time you loop through. Here's an example to help you understand:
var sublist = new List<int> { 1, 2, 3 };
var result = new List<List<int>> { sublist };
//result[0] is now {1, 2, 3}
sublist.Clear();
//result[0] is now {}
result.Add(sublist);
//result[0], result[1], and sublist are the same instance

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.

Multi-Dimensional Data Structures in 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.

Categories