using System;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
int[,] x = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 10, 11, 12 } };
foreach (var i in x)
{
foreach (var j in i)
{
Console.WriteLine(j);
}
}
}
}
}
I noticed that var i in x flattens the array so it generates the following errors for the second foreach.
Error 1 foreach statement cannot operate on variables of type 'int'
because 'int' does not contain a public definition for 'GetEnumerator'
Is it possible to prevent foreach from flattening rectangular arrays?
Multidimensional array is, in some sense, a one-dimensional array that uses dimension information for accessing data as if they were really stored in two dimensions. Because of that when accessed by many methods (e.g. from class Array) and foreach iteration it's being treated as one-dimensional array, as this is the actual layout in memory. Otherwise during iteration new one-dimensional arrays would need to be created for every row.
You can try doing following things to achieve what you want:
Using jagged array instead of multidimensional one: int[][].
Creating extension method IEnumerable<IEnumerable<T>> ByRows<T>(this T[,] array) that would create iterator that does the proper iteration over rows. Obviously rows would either be a single-dimensional arrays, or another custom iterator that would iterate over contents of the row.
Skip the foreach entirely and use two nested for loops.
If you have a jagged array it won't behave this way (ie an array declared as int[][] rather than int[,]) Foreach is designed to enumerate each element and in the 2D array each element is an int, not an int array (despite the static initializer making it look like it's an array of arrays it's not). If you want to make it work as is (with a 2D array), I suggest using a conventional for loop instead of foreach.
The problem isn't so much in foreach, it's in the implementation of the enumerator returned from GetEnumerator. What it's doing is treating the multidimensional array as one contiguous array of values (and that's what it is in memory).
If you think about how you'd have to implement an enumerator so that it gave you your desired behaviour, it would basically be enumerating over an IEnumerable. This is effectively an array of arrays. C# represents this with jagged arrays, or int[][], as others have mentioned.
Conversely, multidimensional arrays are modelled in C# as one piece of memory that you index with two indices. You can't index the multidimensional array with one index and get back an array, as you can with jagged arrays. In fact, if you try to index a multidimensional array with one index, you get a compile error. You could implement the multidimensional array as a single dimension array, and do the math to translate a two dimensional index into a single dimensional index yourself.
Related
I have just noticed that a multidimensional array in C# does not implement IEnumerable<T>, while it does implement IEnumerable. For single-dimensional arrays, both IEnumerable<T> and IEnumerable are implemented.
Why this difference? If a multi-dimensional array is IEnumerable, surely it should also implement the generic version? I noticed this because I tried to use an extension method on a multidimensional array, which fails unless you use Cast<T> or similar; so I can definitely see the an argument for making multidimensional arrays implement IEnumerable<T>.
To clarify my question in code, I would expect the following code to print true four times, while it actually prints true, false, true, true:
int[] singleDimensionArray = new int[10];
int[,] multiDimensional = new int[10, 10];
Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiDimensional is IEnumerable<int>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiDimensional is IEnumerable);
The CLR has two different kinds of arrays: vectors which are guaranteed to be one-dimensional with a lower bound of 0, and more general arrays which can have non-zero bounds and a rank other than 0.
From section 8.9.1 of the CLI spec:
Additionally, a created vector with
element type T, implements the
interface
System.Collections.Generic.IList<U>
(ยง8.7), where U := T.
I have to say it seems pretty weird to me. Given that it already implements IEnumerable I don't see why it shouldn't implement IEnumerable<T>. It wouldn't make as much sense to implement IList<T>, but the simple generic interface would be fine.
If you want this, you could either call Cast<T> (if you're using .NET 3.5) or write your own method to iterate through the array. To avoid casting you'd have to write your own method which found the lower/upper bounds of each dimension, and fetched things that way. Not terribly pleasant.
There is a workaround: you can convert any multidimensional array to an IEnumerable
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this Array target)
{
foreach (var item in target)
yield return (T)item;
}
}
Zero bound single dimensional arrays implements both IEnumerable and IEnumerable<T>, but multi-dimensional arrays, unfortunately, implements only IEnumerable. The "workaround" by #Jader Dias indeed converts a multidimensional array to IEnumerable<T> but with a huge cost: every element of an array will be boxed.
Here is a version that won't cause boxing for every element:
public static class ArrayExtensions
{
public static IEnumerable<T> ToEnumerable<T>(this T[,] target)
{
foreach (var item in target)
yield return item;
}
}
Jagged arrays don't support IEnumerable<int> either, because multidimensional structures aren't really an array of a type, they are an array of an array of a type:
int[] singleDimensionArray = new int[10];
int[][] multiJagged = new int[10][];
Debug.WriteLine(singleDimensionArray is IEnumerable<int>);
Debug.WriteLine(multiJagged is IEnumerable<int[]>);
Debug.WriteLine(singleDimensionArray is IEnumerable);
Debug.WriteLine(multiJagged is IEnumerable);
Prints true, true, true, true.
Note: int[,] isn't an IEnumerable<int[]>, that's for the reasons specified in the other answer, namely there's no generic way to know which dimension to iterate over. With jagged arrays, there isn't as much room for interpretation because the syntax is pretty clear about it being an array of arrays.
Think inversely. The 2d array already exists. Just enumerate it. Create a 2d array with score and place of an initial array or marks, including duplicate values.
int[] secondmarks = {20, 15, 31, 34, 35, 50, 40, 90, 99, 100, 20};
IEnumerable<int> finallist = secondmarks.OrderByDescending(c => c);
int[,] orderedMarks = new int[2, finallist.Count()];
Enumerable.Range(0, finallist.Count()).ToList().ForEach(k => {orderedMarks[0, k] = (int) finallist.Skip(k).Take(1).Average();
orderedMarks[1, k] = k + 1;});
Enumerable.Range(0, finallist.Count()).Select(m => new {Score = orderedMarks[0, m], Place = orderedMarks[1, m]}).Dump();
Results:
Score Place
100 1
99 2
90 3
50 4
40 5
35 6
34 7
31 8
20 9
20 10
15 11
This question already has answers here:
Sorting an array related to another array
(4 answers)
Closed 6 years ago.
I have multiple arrays, the values in the arrays need to stay together column by column. I want to quicksort then binary search the first array then display all of the values from the other arrays according to the search on the first array. But if I sort the first array then the values from the other arrays are no longer in the correct place.
(Example, not real data) The unsorted but correct position of the data looks like this.
array1{5,2,3,1,4}
array2{6,9,1,7,8}
array3{2,4,1,5,4}
when the first array is sorted it should look like this.
array1{1,2,3,4,5}
array2{7,9,1,8,6}
array3{5,4,1,4,2}
then if 2 is searched it should display like this.
array1{2}
array2{9}
array3{4}
My arrays are in double[].
First thing; linked arrays like this suggests you might find it easier if you modelled the problem differently. For example, if the arrays are x, y, and x coordinates, then you might be better off using a class like this;
public class Point3d { public int x; public int y; public int z; }
Then sort the array of points by x;
Array.Sort(listOfPoints, (d1,d2) => d1.CompareTo(d2));
In general, lining things up like this suggests you've actually got records on the vertical, and your code may benefit from treating it like that.
int index = 0;
// save original positions
var lookup = array.ToDictionary(x => x, x => index++);
// sort array
Array.Sort(array1);
foreach (var item in array)
{
int originalIndex = lookup[item];
... array2[originalIndex]
}
Actually, having this dictionary, you don't need to sort the array. It can be even faster because building a dictionary is O(N) and accessing an element is O(1) (both amortized).
I want to write a function which return an array which contain a for loop that enumerates some value I want to store them in to an array. I tried this
public int[] a()
{
int[] b=new int []{};
for(int i=0;i<10;i++)
{
b[i]=i {Index out of range exception comes}
}
return b;
}
I don't like to use enumerable.range() because of performance issue.
I want to keep the array size empty.
In your case you need an array with 10 elements in it. In some languages you could do what you are trying to do (JavaScript being one). Let's assume you could extend an array in C# then your code would allocate space for one element at a time in each iteration of the loop resulting in the allocation of 10 elements. Optimally this would be as fast as allocating 10 elements in one go.
However that's probably unlikely and it's never going to be faster than requesting once for all of them to be allocated. So in other words there's no performance gain to be found by not simply allocating all 10 elements in one go
public int[] a()
{
int[] b=new int [10];
for(int i=0;i<b.Length;i++)
{
b[i]=i;
}
return b;
}
However a much more readable approach would be
public int[] a()
{
return Enumerable.Range(0,10).ToArray();
}
int[] b=new int []{}; means your array b[] is zero length. You get an index out of range exception on b[i]=i because there are no elements. You're effectively doing b[0]=0 but element 0 does not exist.
I'm looking for a way to set every value in a multidimensional array to a single value. The problem is that the number of dimensions is unknown at compile-time - it could be one-dimensional, it could be 4-dimensional. Since foreach doesn't let you set values, what is one way that I could achieve this goal? Thanks much.
While this problem appears simple on the surface, it's actually more complicated than it looks. However, by recognizing that visiting every position in a multidimensional (or even jagged) array is a Cartesian product operation on the set of indexes of the array - we can simplify the solution ... and ultimately write a more elegant solution.
We're going to leverage Eric Lippert's LINQ Cartesian Product implementation to do the heavy lifting. You can read more about how that works on his blog if you like.
While this implementation is specific to visiting the cells of a multidimensional array - it should be relatively easy to see how to extend it to visit a jagged array as well.
public static class EnumerableExt
{
// Eric Lippert's Cartesian Product operator...
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct =
new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
}
class MDFill
{
public static void Main()
{
// create an arbitrary multidimensional array
Array mdArray = new int[2,3,4,5];
// create a sequences of sequences representing all of the possible
// index positions of each dimension within the MD-array
var dimensionBounds =
Enumerable.Range(0, mdArray.Rank)
.Select(x => Enumerable.Range(mdArray.GetLowerBound(x),
mdArray.GetUpperBound(x) - mdArray.GetLowerBound(x)+1));
// use the cartesian product to visit every permutation of indexes
// in the MD array and set each position to a specific value...
int someValue = 100;
foreach( var indexSet in dimensionBounds.CartesianProduct() )
{
mdArray.SetValue( someValue, indexSet.ToArray() );
}
}
}
It's now trivial to factor this code out into a reusable method that can be used for either jagged or multidimensional arrays ... or any data structure that can be viewed as a rectangular array.
Array.Length will tell you the number of elements the array was declared to store, so an array of arrays (whether rectangular or jagged) can be traversed as follows:
for(var i=0; i<myMDArray.Length; i++)
for(var j=0; j < myMDArray[i].Length; i++)
DoSomethingTo(myMDArray[i][j]);
If the array is rectangular (all child arrays are the same length), you can get the Length of the first array and store in a variable; it will slightly improve performance.
When the number of dimensions is unknown, this can be made recursive:
public void SetValueOn(Array theArray, Object theValue)
{
if(theArray[0] is Array) //we haven't hit bottom yet
for(int a=0;a<theArray.Length;a++)
SetValueOn(theArray[a], theValue);
else if(theValue.GetType().IsAssignableFrom(theArray[0].GetType()))
for(int i=0;i<theArray.Length;i++)
theArray[i] = theValue;
else throw new ArgumentException(
"theValue is not assignable to elements of theArray");
}
I think there is no direct way of doing this, so you'll need to use the Rank property to get the number of dimensions and a SetValue method (that takes an array with index for every dimension as argument).
Some code snippet to get you started (for standard multi-dimensional arrays):
bool IncrementLastIndex(Array ar, int[] indices) {
// Return 'false' if indices[i] == ar.GetLength(i) for all 'i'
// otherwise, find the last index such that it can be incremented,
// increment it and set all larger indices to 0
for(int dim = indices.Length - 1; dim >= 0; dim--) {
if (indices[dim] < ar.GetLength(dim)) {
indices[dim]++;
for(int i = dim + 1; i < indices.Length; i++) indices[i] = 0;
return;
}
}
}
void ClearArray(Array ar, object val) {
var indices = new int[ar.Rank];
do {
// Set the value in the array to specified value
ar.SetValue(val, indices);
} while(IncrementLastIndex(ar, indices));
}
The Array.Clear method will let you clear (set to default value) all elements in a multi-dimensional array (i.e., int[,]). So if you just want to clear the array, you can write Array.Clear(myArray, 0, myArray.Length);
There doesn't appear to be any method that will set all of the elements of an array to an arbitrary value.
Note that if you used that for a jagged array (i.e. int[][]), you'd end up with an array of null references to arrays. That is, if you wrote:
int[][] myArray;
// do some stuff to initialize the array
// now clear the array
Array.Clear(myArray, 0, myArray.Length);
Then myArray[0] would be null.
Are you saying that you want to iterate through each element and (if available) each dimension of an array and set each value along the way?
If that's the case you'd make a recursive function that iterates the dimensions and sets values. Check the Array.Rank property on MSDN and the Array.GetUpperBound function on MSDN.
Lastly, I'm sure generic List<T> has some sort of way of doing this.
Is there a better way to examine whether two string arrays have the same contents than this?
string[] first = new string[]{"cat","and","mouse"};
string[] second = new string[]{"cat","and","mouse"};
bool contentsEqual = true;
if(first.Length == second.Length){
foreach (string s in first)
{
contentsEqual &= second.Contains(s);
}
}
else{
contentsEqual = false;
}
Console.WriteLine(contentsEqual.ToString());// true
Enumerable.SequenceEquals if they're supposed to be in the same order.
You should consider using the intersect method. It will give you all the matching values and then you can just compare the count of the resulting array with one the arrays that were compared.
http://msdn.microsoft.com/en-us/library/system.linq.enumerable.intersect.aspx
This is O(n^2). If the arrays have the same length, sort them, then compare elements in the same position. This is O(n log n).
Or you can use a hash set or dictionary: insert each word in the first array, then see if every word in the second array is in the set or dictionary. This is O(n) on average.
Nothing wrong with the logic of the method, but the fact that you're testing Contains for each item in the first sequence means the algorithm runs in O(n^2) time in general. You can also make one or two other smaller optimisations and improvements
I would implement such a function as follows. Define an extension method as such (example in .NET 4.0).
public static bool SequenceEquals<T>(this IEnumerable<T> seq1, IEnumerable<T> seq2)
{
foreach (var pair in Enumerable.Zip(seq1, seq2)
{
if (!pair.Item1.Equals(pair.Item2))
return;
}
return false;
}
You could try Enumerable.Intersect: http://msdn.microsoft.com/en-us/library/bb460136.aspx
The result of the operation is every element that is common to both arrays. If the length of the result is equal to the length of both arrays, then the two arrays contain the same items.
Enumerable.Union: http://msdn.microsoft.com/en-us/library/bb341731.aspx would work too; just check that the result of the Union operation has length of zero (meaning there are no elements that are unique to only one array);
Although I'm not exactly sure how the functions handle duplicates.