Custom iteration for multi-dimensional arrays? - c#

Something like:
forelement (element G_Element, Grid)
{
Grid[G_Element.dim1, G_Element.dim2] =
new clsGridElement(G_Element.dim1, G_Element.dim2);
}
instead of
for (int X = 0; X < GridWidth; X++)
for (int Y = 0; Y < GridHeight; Y++)
Grid[X, Y] = new clsGridElement(X, Y);
If something doesn't innately exist, is that something that could be created?
Thanks,
Tim

You could do this - just make a custom type that exposes these, and use a regular foreach:
public class TwoDimensionalIterator
{
public TwoDimensionalIterator(int i, int j)
{
this.Dim1 = i; this.Dim2 = j;
}
public int Dim1 { get; private set; }
public int Dim2 { get; private set; }
}
Then make an extension method somewhere to return an enumerable of this:
public static IEnumerable<TwoDimensionalIterator> IterateTwoDim<T>(this T[,] array)
{
for (int i=0;i<array.GetLength(0);++i)
for (int j=0;i<array.GetLength(1);++j)
yield return new TwoDimensionalIterator(i,j);
}
With this, you could then do:
foreach(var index in Grid.IterateTwoDim())
{
Grid[index.Dim1, index.Dim2] = new clsGridElement(index.Dim1, index.Dim2);
}

Not sure exactly what you are trying to do here, or why, or what you expect to get from it, but if you implement your own iterator than implements the IEnumerator interface then you could create something that would hit every cell in your 2D (or more) collection.
Of course, you won't actually gain anything performance-wise from doing this versus just using nested loops, but I guess it'd be syntactic sugar.

Such creation of indexes can be obtained by using "Cartesian product" of all indexes. Here is sample based on Is there a good LINQ way to do a cartesian product? (courtesy of the Eric Lippert):
var allIndexes = from dim1 in Enumerable.Range(0, Grid.GetLength(0))
from dim2 in Enumerable.Range(0, Grid.GetLength(1))
select new {dim1, dim2};
foreach (var G_Element in allIndexes)
{
Grid[G_Element.dim1, G_Element.dim2] =
new clsGridElement(G_Element.dim1, G_Element.dim2);
}

Related

C#: My Sorting Method/ Printing class does not print the first entry

I have implemented my own selection sort method that seems to be doing it's job for the most part; However, when I am printing files to an excel sheet the printer does not print the first item. I am unsure whether or not the sort method is the source of the problem. My test method for my sort method passes, which is why I am doubting that that is the source. My sort method is shown below. Does it have an error in the scope or order or operations? When I manually move through it on paper everything sorts properly.
public bool sortMaterial()
{
for (int i = 0; i < salesList.Count - 2; i++)
{
Sales curr = salesList[i];
Sales temp;
Sales min = curr;
int swap = 0;
for (int j = i + 1; j < salesList.Count; j++ )
{
temp = salesList[j];
if (String.Compare(temp.material, min.material) == -1)
{
min = temp;
swap = j;
}
}
salesList[i] = min;
salesList[swap] = curr;
}
return true;
}
A neat way to do custom sorting is by implementing the IComparer<T> interface:
public class SalesMaterialComparer : IComparer<Sales> {
public int Compare(Sales x, Sales y) {
return String.Compare(x.material, y.material);
}
}
You can pass your custom comparer to the LINQ OrderBy() method.
IEnumerable<Sales> salesList;
var myComparer = new SalesMaterialComparer();
var sorted = salesList.OrderBy(s => s, myComparer);

Algorithm: Checking for conditions in 3D array

This one is hard to explain! Sorry for that, but here goes...
I have a 3D array of some data [X][Y][Z], and I like to check for about 10 different combination conditions and keep only data when it's a match... Example:
X Y Z
//myData[1..1000000][1..10][1..10].foo // foo is an int
X[i].Y[ii].Z[iii].foo; // X is a container, Y= 1 to 10 levels. And Z= objects
//I want to apply a "filter" to the Z objects...
Lets say I want to find all combinations where the sum of "foo" is smaller and larger than two numbers, and only keep those Z objects
For next iteration i want to find lets say only where "foo" is a prime number, still keeping only Z objects
And so on for more conditions, resulting in smaller and smaller list.
It doesn't matter in wich order they are performed.
I sort of know how to do it, but I end up in some really nasty loops...
Any Ideas? Maybe adding to another list is faster than deleting from original list?
Thanks in advance!
When you want to chain together logic like this, I think you really want to use Linq. Unfortunately, it can be cumbersome to use Linq on multidimensional arrays. With some helper methods, though, we can convert the data array into something more usable. First, let's build a wrapper class for any object that has 3 dimensions associated with it:
public class ThreeDimensionalArrayExtension<T> {
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public T Value { get; set; }
}
Next, let's write a helper method that converts 3-dimsensional arrays to IEnumerables of the new type:
public static class ThreeDimensionalArrayExtensionMethods {
public static IEnumerable<ThreeDimensionalArrayExtension<T>> ConvertArray<T>(this T[,,] foos) {
for(var x = 0; x < foos.GetLength(0); x++) {
for (var y = 0; y < foos.GetLength(1); y++) {
for (var z = 0; z < foos.GetLength(2); z++) {
yield return new ThreeDimensionalArrayExtension<T> { X = x, Y = y , Z = z, Value = foos[x, y, z] };
}
}
}
}
}
Note that since we are using an iterator block (the yield-return pattern), calling this method does not actually perform any computation.
Now we can use the power of Linq on your 3-dimensional array to filter it however we want!
myData.ConvertArray().Where(d => d.Value.Foo > 5)
.Where(d => IsPrime(d.Value.Foo))
.Where(...);
Edit:
I see that you're using 3 nested classes and not a multidimensional array which I assumed you were using. The goal should still be to convert that object to an IEnumerable upon which you can very easily chain Linq queries to filter or project the data. In your case, you can do:
public static class ThreeDimensionalArrayExtensionMethods {
public static IEnumerable<ThreeDimensionalArrayExtension<X>> ConvertArray(this X[] foos) {
for(var x = 0; x < foos.Count(); x++) {
for (var y = 0; y < foos[x].Count(); y++) {
for (var z = 0; z < foos[x][y].Count(); z++) {
yield return new ThreeDimensionalArrayExtension<T> { X = x, Y = y , Z = z, Value = foos[x][y][z] };
}
}
}
}
}
And then use the same call to ConvertArray followed by the filtering Where clauses described above.
If you don't care about the X/Y/Z indices, you can also just use SelectMany to project the multidimensional list onto a single dimensional list:
X.SelectMany(y => y.SelectMany(z => z)).Where(z => z.Foo > 5);

c# IEnumerable double iteration

This is out of curiosity I want to ask this question...
Here is my code:
for (int i = 0; i < myList.Count - 1; ++i)
{
for (int j = i+1; j < myList.Count; ++j)
{
DoMyStuff(myList[i], myList[j]);
}
}
Pretty simple loop, but obviously it only works with List...
But I was wondering... how can I code this loop in order to make it independent of the collection's type (deriving from IEnumerable...)
My first thought:
IEnumerator it1 = myList.GetEnumerator();
while (it1.MoveNext())
{
IEnumerator it2 = it1; // this part is obviously wrong
while (it2.MoveNext())
{
DoMyStuff(it1.Current, it2.Current);
}
}
Because enumerators don't have an efficient way of getting the n'th element, your best bet is to copy the enumerable into a list, then use your existing code:
void CrossMap<T>(IEnumerable<T> enumerable)
{
List<T> myList = enumerable.ToList();
for (int i = 0; i < myList.Count - 1; ++i)
{
for (int j = i+1; j < myList.Count; ++j)
{
DoMyStuff(myList[i], myList[j]);
}
}
}
However, there is a rather tricksie hack you can do with some collection types. Because the enumerators of some of the collection types in the BCL are declared as value types, rather than reference types, you can create an implicit clone of the state of an enumerator by copying it to another variable:
// notice the struct constraint!
void CrossMap<TEnum, T>(TEnum enumerator) where TEnum : struct, IEnumerator<T>
{
while (enumerator.MoveNext())
{
TEnum enum2 = enumerator; // value type, so this makes an implicit clone!
while (enum2.MoveNext())
{
DoMyStuff(enumerator.Current, enum2.Current);
}
}
}
// to use (you have to specify the type args exactly)
List<int> list = Enumerable.Range(0, 10).ToList();
CrossMap<List<int>.Enumerator, int>(list.GetEnumerator());
This is quite obtuse, and quite hard to use, so you should only do this if this is performance and space-critical.
Here is a way that will truly use the lazy IEnumerable paradigm to generate a stream of non-duplicated combinations from a single IEnumerable input. The first pair will return immediately (no cacheing of lists), but there will be increasing delays (still imperceptible except for very high values of n or very expensive IEnumerables) during the Skip(n) operation which occurs after every move forward on the outer enumerator:
public static IEnumerable<Tuple<T, T>> Combinate<T>(this IEnumerable<T> enumerable) {
var outer = enumerable.GetEnumerator();
var n = 1;
while (outer.MoveNext()) {
foreach (var item in enumerable.Skip(n))
yield return Tuple.Create(outer.Current, item);
n++;
}
}
Here is how you would use it in your case:
foreach(var pair in mySource.Combinate())
DoMyStuff(pair.Item1, pair.Item2);
Postscript
Everyone has pointed out (here and elsewhere) that there is no efficient way of getting the "nth" element of an IEnumerable. This is partly because IEnumerable does not require there to even be an underlying source collection. For example, here's a silly little function that that dynamically generates values for an experiment as quickly as they can be consumed, and continues for a specified period of time rather than for any count:
public static IEnumerable<double> Sample(double milliseconds, Func<double> generator) {
var sw = new Stopwatch();
var timeout = TimeSpan.FromMilliseconds(milliseconds);
sw.Start();
while (sw.Elapsed < timeout)
yield return generator();
}
There are extension methods Count() and ElementAt(int) that are declared on IEnumerable<T>. They are declared in the System.Linq namespace, which should be included by default in your .cs files if you are using any C# version later than C# 3. That means that you could you just do:
for (int i = 0; i < myList.Count() - 1; ++i)
{
for (int j = i+1; j < myList.Count(); ++j)
{
DoMyStuff(myList.ElementAt(i), myList.ElementAt(j));
}
}
However, note that these are methods, and will be called over and over again during iteration, so you might want to save their result to variables, like:
var elementCount = myList.Count();
for (int i = 0; i < elementCount - 1; ++i)
{
var iElement = myList.ElementAt(i);
for (int j = i+1; j < elementCount; ++j)
{
DoMyStuff(iElement, myList.ElementAt(j));
}
}
You could also try some LINQ that will select all pair of elements that are eligible, and then use simple foreach to call the processing, something like:
var result = myList.SelectMany((avalue, aindex) =>
myList.Where((bvalue, bindex) => aindex < bindex)
.Select(bvalue => new {First = avalue, Second = bvalue}));
foreach (var item in result)
{
DoMyStuff(item.First, item.Second);
}
I'd write against IEnumerable<T> and pass a delegate for the indexing operation:
public static void DoStuff<T>(IEnumerable<T> seq, Func<int, T> selector)
{
int count = seq.Count();
for (int i = 0; i < count - 1; ++i)
{
for (int j = i+1; j < count; ++j)
{
DoMyStuff(selector(i), selector(j));
}
}
}
You can call it using:
List<T> list = //whatever
DoStuff(list, i => list[i]);
If you restrict the collection argument to ICollection<T> you can use the Count property instead of using the Count() extension method.
Not really efficient, but readable:
int i = 0;
foreach( var item1 in myList)
{
++i;
foreach( var item2 in myList.Skip(i))
DoMyStuff(item1, item2);
}
You can do it fairly succinctly using IEnumerable.Skip(), and it might even be fairly fast compared with copying the list into an array IF the list is short enough. It's bound to be a lot slower than the copying for lists of a sufficient size, though.
You'd have to do some timings with lists of various sizes to see where copying to an array becomes more efficient.
Here's the code. Note that it's iterating an enumerable twice - which will be ok if the enumerable is implemented correctly!
static void test(IEnumerable<int> myList)
{
int n = 0;
foreach (int v1 in myList)
{
foreach (int v2 in myList.Skip(++n))
{
DoMyStuff(v1, v2);
}
}
}

C# Sorting Strings only on first letter

I'm trying to sort a list of strings in alphabetical order in C#. My code looks like this:
public static List<Result> sort(List<Result> listToSort)
{
int listSize = listToSort.Count;
for (int i = 0; i < listSize; i++)
{
for (int j = 0; j < listSize; j++)
{
if (listToSort[i].SN[0] < listToSort[j].SN[0])
{
Result tempValue = listToSort[j];
listToSort[j] = listToSort[i];
listToSort[i] = tempValue;
}
}
}
return listToSort;
}
But it's only sorting it based on the first letter of a string. In other words, if I have a list like this:
donald, abby, dave, bob, sam, pete
It will sort it like so:
abby, bob, donald, dave, pete, sam
One would expect 'dave' to come before 'donald'..
Any ideas?
Currently you are only sorting by the first letter that is why you are seeing this result. You can use Enumerable.OrderBy - LINQ
List<Result> sortedList = listToSort.OrderBy(r=> r.SN).ToList();
Or for your current code you can modify your check to:
if (string.Compare(listToSort[i].SN,listToSort[j].SN) < 0)
How about using LINQ for this:
return listToSort.OrderBy(report => report.SN)
I'm assuming your Report class has a string property you want the list to be sorted by?
EDIT
Didn't notice that you'd already specified the SN property, have amended my answer.
public static List<Result> sort(List<Result> listToSort)
{
return listToSort.OrderBy(x=>x.SN[0]).ToList();
}
You're only ever evaluating the first letter. Try using the traditional sorting method:
public static void Sort(List<Result> listToSort)
{
listToSort.Sort(new ResultComparator());
}
public class ResultComparator : IComparer<Result>
{
public int Compare(Result x, Result y)
{
if (x == null && y == null) return 0;
if (x == null) return 1;
if (y == null) return 0;
// compare based in SN
return string.Compare(x.SN, y.SN);
}
}
Take a look at this part:
for (int i = 0; i < listSize; i++)
{
for (int j = 0; j < listSize; j++)
{
if (listToSort[i].SN[0] < listToSort[j].SN[0])
{
You are
only comparing on SN[0]. If SN is a string then that explains your main result.
always using the same compare, whether i < j or i > j
Best thing to do is to use a built-in sort. Linq's OrderBy(lambda) is the easiest but it creates a new list. For an in-place sort, use List<T>.Sort(Comparer).
If you do have to do it yourself, look up a good sorting algorithm (wikipedia).
It was happened because of comparing character of the first string (listToSort[i].SN[0] => which produces the first character of your input). If you want to compare the string values, you should use string.Compare() method.
--SJ

Find all the variations of K elements from a set of n

I am stuck with this problem of trying to generate all the variations of K elements from the set [1..N]. I also had an idea that I can do that with k levels of nested loops and tried to do that recursively, but without success.
I have this function:
public static void PrintVariation(int n, int k, int[] array)
{
//when k = 2
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
Console.WriteLine("{0}, {1}", array[i], array[j]);
}
}
}
But what am I supposed to do when k has a random value?
Here is my hint: I think you are on the right track using recursion.
private List<Element[]> getVariations(int k, Element[] elements)
{
// ... ^_^
// use getVariations with less elements in here
}
I'm not sure I follow you though, but this is what I think you should do:
Create a function that will 'generate a variation of K elements from the set [1..N]' It should return that variation.
Call that function in a for-loop in another method that would add it to a generic collection. You may add another routine that would check if the variation generated by the function already exists in the collection and skip adding that variation to the collection.
public static List<List<T>> GetVariations<T>(int k, List<T> elements)
{
List<List<T>> result = new List<List<T>>();
if (k == 1)
{
result.AddRange(elements.Select(element => new List<T>() { element }));
}
else
{
foreach (T element in elements)
{
List<T> subelements = elements.Where(e => !e.Equals(element)).ToList();
List<List<T>> subvariations = GetVariations(k - 1, subelements);
foreach (List<T> subvariation in subvariations)
{
subvariation.Add(element);
result.Add(subvariation);
}
}
}
return result;
}

Categories

Resources