C# LINQ query on multidimensional array - c#

How would I use the following LINQ query correctly? I want to create a one-dimensional array that contains only values that are greater than 5. I can't understand why it can't iterate over this multidimensional array, but if I use foreach, it actually iterates.
// Create an multidimensional array, then just put numbers into it and print the array.
int[,] myArr = new int[5,6];
int rows = myArr.GetLength(0);
int cols = myArr.GetLength(1);
for (int i = 0; i < rows; i++)
{
for (int k = 0; k < cols; k++)
{
myArr[i,k] = i + k;
Console.Write(myArr[i,k]);
}
Console.WriteLine("");
}
var highList = from val in myArr where (val > 5) select val;
The error is:
Could not find an implementation of the query pattern for source type 'int[*,*]'. 'Where' not found. Are you missing a reference or a using directive for 'System.Linq'?
I thought this might fix the problem:
public static IEnumerator<int> GetEnumerator(int[,] arr)
{
foreach(int i in arr)
{
yield return i;
}
}
But it doesn't implement the iterator.

The problem is that multi-dimensional (rectangular) arrays implement IEnumerable, but not IEnumerable<T>. Fortunately, you can use Cast to fix that - and Cast gets called automatically if you explicitly specify the type of the range variable:
var highList = from int val in myArr where (val > 5) select val;
Or without the unnecessary brackets:
var highList = from int val in myArr where val > 5 select val;
Or using method calls directly, given that it's a pretty trivial query expression:
var highList = myArr.Cast<int>().Where(val => val > 5);
I think this will box each element, however. You could add your own Cast extension method to avoid that:
public static class RectangularArrayExtensions
{
public static IEnumerable<T> Cast<T>(this T[,] source)
{
foreach (T item in source)
{
yield return item;
}
}
}

Related

Check to see what item in ArrayList is smaller c#

I am trying to make my own multithreaded mergesort algorithm by using an ArrayList. I am familiar with this method in Java but trying to bring it over to c# is not working as planned. I get the following error when trying to compare two ArrayList items Error 1 Operator '<' cannot be applied to operands of type 'object' and 'object'. I know you cannot directly compare two objects like that, in Java you can use compareTo or something like that, is there any equivalent for c#?
Here is the code causing the error in case you need it, bear in mind that I copied this from one of my Java programs that worked with integer arrays.
int size = (last - first) + 1;
ArrayList temp = new ArrayList();
int mid = (first + last) / 2;
int i1 = 0;
int i2 = first;
int i3 = mid + 1;
while(i2 <= mid && i3 <= last)
{
if(list[i2] < list[i3])
temp[i1++] = list[i2++];
else temp[i1++] = list[i3++];
}
while(i2 <= mid)
temp[i1++] = list[i2++];
while(i3 <= last)
temp[i1++] = list[i3++];
i3 = first;
for(i1 = 0; i1 < temp.Count; i1++, i3++)
list[i3] = temp[i1];
I think just use a SortedList of ints.
var sl = new SortedList();
sl.Add(15, 15);
sl.Add(443, 443);
sl.Add(2, 2);
sl.Add(934, 934);
sl.Add(55, 55);
foreach (var item in sl.Values)
{
Console.WriteLine(item); // Outputs 2, 15, 55, 443, 934
}
Or else a generic List and call Sort (better perf I think).
var list = new List<int>();
list.Add(5);
list.Add(1);
list.Add(59);
list.Add(4);
list.Sort();
foreach (var element in list)
{
Console.WriteLine(element); // Outputs 1, 4, 5, 59
}
I would suggest looking into the IComparer<T> interface. You can make a version of your MergeSort algorithm that takes an IComparer<T> which can be used to compare the objects for sorting. It would probably give you similar functionality to what you are used to.
You could do this in addition to defining a version of MergeSort that restricts the type to IComparable<T>. This way, between both versions of the function, you can handle objects that implement the interface already and also allow your users to provide a comparison for objects that don't implement it.
You could put the MergeSort in as an Extension Method on the IList<T> interface as such.
public static class MergeSortExtension
{
public static IList<T> MergeSort<T>(this IList<T> list) where T : IComparable<T>
{
return list.MergeSort(Comparer<T>.Default);
}
public static IList<T> MergeSort<T>(this IList<T> list, IComparer<T> comparer)
{
// Sort code.
}
}
You could cast each item to IComparable or do an as IComparable and check for null (casting will throw an exception if the object instance doesn't implement the interface). But what #DavidG L suggested probably the way to go. But make a constraint on T that it must implement IComparable.
Taking all of your suggestions into account I have come up with the following solution:
public static void merge(List<T> list , int first, int last) {
int size = (last - first) + 1;
List<T> temp = new List<T>();
IEnumerable<IComparable> sorter = (IEnumerable<IComparable>)list;
int mid = (first + last) / 2;
int i1 = 0;
int i2 = first;
int i3 = mid + 1;
while(i2 <= mid && i3 <= last)
{
if (sorter.ElementAt(i2).CompareTo(sorter.ElementAt(i3)) < 0)
temp[i1++] = list[i2++];
else temp[i1++] = list[i3++];
}
while(i2 <= mid)
temp[i1++] = list[i2++];
while(i3 <= last)
temp[i1++] = list[i3++];
i3 = first;
for(i1 = 0; i1 < temp.Count; i1++, i3++)
list[i3] = temp[i1];
}
Thank you for all the help, I do not get any errors anymore.
The problem is that ArrayList is not a generic collection, so it allows to call only object's methods on any item. You can use LINQ to cast to generic IEnumerable<int>, then you will be able to call methods on int, including comparing and ordering:
ArrayList al = new ArrayList();
al.Add(1);
al.Add(2);
IEnumerable<int> coll = al.Cast<int>();
if (coll.ElementAt(0) < coll.ElementAt(1))
// ...
or:
var ordered = coll.OrderBy(n => n).ToList();
If your ArrayList contains objects of different types, you should use OfType<int> to filetr out ints, but the proper way would be to use a typed collection like List<int> instead of ArrayList.

Casting a generic IEnumerable to a list

I'm splitting a list of (in this example) approx. 190000 items into chunks of 5000 items.
so instead of: List<Object>, count 190000
it becomes: List<List<Object>>, Count 28(Count 5000))
I do this with the following code:
public static IEnumerable<List<Object>> Split(this IEnumerable<Object> sourceList, int chunkSize)
{
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
List<List<Object>> result = new List<List<object>>();
for (int i = 0; i < numberOfLists; i++)
{
List<Object> subList = new List<Object>();
subList = sourceList.Skip(i * chunkSize).Take(chunkSize).ToList();
result.Add(subList);
}
return result;
}
I call this method (which resides in a helper class) like follows;
var chunkList = (IEnumerable<List<MyObjectClass>>)MyHelper.Split(myObjectList, 5000);
In the above line I explicitly cast the list, that fails in an InvalidCastException. When i use the as operator like follows;
var chunkList = MyHelper.Split(myObjectList, 5000) as IEnumerable<List<MyObjectClass>>;
the result is null.
I expected I could use
List<List<MyObjectClass>> chunkList = MyHelper.Split(myObjectList, 5000) as List<List<MyObjectClass>>
I would like to keep the splitter method as generic as possible. The question is how I can cast the return value correctly. Can someone point out to me how to do this?
Thanks in advance.
As others have stated, the problem is that you are attempting to use the type parameter or List<T> in a variant manner, which is not possible. Instead of this you need to make the splitting method generic so that it has its own type parameter that matches that of the list.
That said, you can turn the method into an iterator block so that it only produces the sub-lists on demand:
public static IEnumerable<List<T>> Partition<T>(this IEnumerable<T> source,
int chunkSize)
{
while (source.Any())
{
yield return source.Take(chunkSize).ToList();
source = source.Skip(chunkSize);
}
}
This would be used as
var chunkList = sourceList.Partition(5000);
Note that the above version is free of the off-by-one error that your original code and the solutions based on it all share.
If you don't care about lazy evaluation there is also the possibility of using this trick with GroupBy to do the partitioning:
int i = 0;
var chunkList = sourceList
.GroupBy(o => i++ / chunkSize) // group into partitions
.Select(Enumerable.ToList) // transform each partition into a List
.ToList() // force evaluation of query right now
you can use type parameter instead of object
public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> sourceList, int chunkSize) {
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
List<List<T>> result = new List<List<T>>();
for (int i = 0; i < numberOfLists; i++)
{
result.Add(sourceList.Skip(i * chunkSize).Take(chunkSize));
}
return result;
}
so for use
IEnumerable<List<MyObjectClass>> chunkList = myObjectClassList.Split(5000);
Instead of taking IEnumerable<Object> as parameter and returning IEnumerable<List<Object>> make your method generic:
public static IEnumerable<List<T>> Split<T>(this IEnumerable<T> sourceList, int chunkSize)
{
int numberOfLists = (sourceList.Count() / chunkSize) + 1;
var result = new List<List<T>>(numberOfLists);
for (int i = 0; i < numberOfLists; i++)
{
result.Add(sourceList.Skip(i * chunkSize).Take(chunkSize).ToList());
}
return result;
}
You can also use Partition method from moreLINQ library. It is more efficient then your solution, because using Skip().Take() causes unnecessary iteration over the same set of elements every time.

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

Is there another way to take N at a time than a for loop?

Is there a more elegant way to implement going 5 items at a time than a for loop like this?
var q = Campaign_stats.OrderByDescending(c=>c.Leads).Select(c=>c.PID).Take(23);
var count = q.Count();
for (int i = 0; i < (count/5)+1; i++)
{
q.Skip(i*5).Take(5).Dump();
}
for(int i = 0; i <= count; i+=5)
{
}
So you want to efficiently call Dump() on every 5 items in q.
The solution you have now will re-iterate the IEnumerable<T> every time through the for loop. It may be more efficient to do something like this: (I don't know what your type is so I'm using T)
const int N = 5;
T[] ar = new T[N]; // Temporary array of N items.
int i=0;
foreach(var item in q) { // Just one iterator.
ar[i++] = item; // Store a reference to this item.
if (i == N) { // When we have N items,
ar.Dump(); // dump them,
i = 0; // and reset the array index.
}
}
// Dump the remaining items
if (i > 0) {
ar.Take(i).Dump();
}
This only uses one iterator. Considering your variable is named q, I'm assuming that is short for "query", which implies this is against a database. So using just one iterator may be very beneficial.
I may keep this code, and wrap it up in an extension method. How about "clump"?
public static IEnumerable<IEnumerable<T>> Clump<T>(this IEnumerable<T> items, int clumpSize) {
T[] ar = new T[clumpSize];
int i=0;
foreach(var item in items) {
ar[i++] = item;
if (i == clumpSize) {
yield return ar;
i = 0;
}
}
if (i > 0)
yield return ar.Take(i);
}
Calling it in the context of your code:
foreach (var clump in q.Clump(5)) {
clump.Dump();
}
try iterating by 5 instead!
for(int i = 0; i < count; i += 5)
{
//etc
}
Adding more LINQ with GroupBy and Zip:
q
// add indexes
.Zip(Enumerable.Range(0, Int32.MaxValue),(a,index)=> new {Index=index, Value=a})
.GroupBy(m=>m.Index /5) // divide in groups by 5 items each
.Select(k => {
k.Select(v => v.Value).Dump(); // Perform operation on 5 elements
return k.Key; // return something to satisfy Select.
});

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