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.
Related
I am trying to store each iteration of an array as it is being sorted through. For some reason the jagged array I return just becomes an array of the final sorted array. My code is below I cannot figure out why any help would be really appreciated. Thanks.
namespace SortingUI.Utils
{
public class Sorting
{
public static int[][] SortInt(int[] originalArray)
{
int length = originalArray.Length;
int tempVal, smallest;
int[][] iterations = new int[length-1][];
for (int i = 0; i < length - 1; i++)
{
smallest = i;
for (int j = i + 1; j < length; j++)
{
if (originalArray[j] < originalArray[smallest])
{
smallest = j;
}
}
tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
iterations[i] = originalArray;
}
return iterations;
}
}
}
If i understand your problem, the reason you are getting the same values (and not a snapshot) is because you are storing a reference to the array, and not a copy of the values themselves.
Arrays are reference types, so when you assign them to another variable you are only copying reference and not the contents. If you change the contents, all the references will reflect that
You can make use of Array.Copy to copy the values at the point in time from the originalArray
...
var tempVal = originalArray[smallest];
originalArray[smallest] = originalArray[i];
originalArray[i] = tempVal;
// Create some new memory
iterations[i] = new int[originalArray.Length];
// Copy the contents
Array.Copy(originalArray, iterations[i], originalArray.Length);
Note this is totally untested and i have no idea if the rest of your code is working as intended
Additional Resources
Array.Copy Method
Copies a range of elements in one Array to another Array and performs
type casting and boxing as required.
Arrays (C# Programming Guide)
Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable,
you can use foreach iteration on all arrays in C#.
I have an array with Length = 3 and with values, for example {1,2,3}.
I need to dynamically resize it.
I know that I can use List or
Array.Resize(). But I need to know how to implement my own resize method?
You can try the following code. Create new array with new size and copy the old array data to the newly created array.
public static Array ResizeArray (Array oldArray, int newSize)
{
int oldSize = oldArray.Length;
Type elementType = oldArray.GetType().GetElementType();
Array newArray = Array.CreateInstance(elementType,newSize);
int preserveLength = System.Math.Min(oldSize,newSize);
if (preserveLength > 0)
{
Array.Copy (oldArray,newArray,preserveLength);
}
return newArray;
}
If this is just for practice then do it. but i suggest you use .Net Array.Resize() if you want to use it in your code. usually .Net libraries are best implemented and optimized.
Any way...you can do it with generic method
private static void Resize<T>(ref T[] array,int size)
{
T[] token = array.Take(size).ToArray(); // attempt to take first n elements
T[] temp = new T[size]; // create new reference
token.CopyTo(temp, 0); // copy array contents to new array
array = temp; // change reference
}
Note that you cannot do this without parameter ref. (The other way is to return array of course)
You may think arrays are passed by reference. thats true. But the references it self are passed by value. so whenever you try to change the reference it does not refer to the original array anymore. you can only change the contents. To make this possible you have to use ref to directly pass the reference into method.
About the code:
{1,2,3} if you resize it to 2 obviously it will remove the last parameter. so you will have {1,2}
if you resize it to 4 then it will give the array with new default values. either null for reference types or 0 for value types (false for Boolean type). here you will have {1,2,3,0}
int[] array = new[] {1, 2, 3};
Resize(ref array,4);
Console.WriteLine(array.Length); // outputs 4
Well, you may look on Array.Resize source code before making your own implementation =)
http://referencesource.microsoft.com/#mscorlib/system/array.cs,71074deaf111c4e3
If you want to resize the array use the build in method Array.Resize().It will be easier and faster.
If you need a dynamically sized data structure, use List for that.
You can always do array.ToList() -> fill the list and do .ToArray() later.
Make an array of the new desired size, copy all items over. Make the variable that referenced your old array reference the new one.
Code from MSDN:
public static void Resize<T>(ref T[] array, int newSize) {
if (newSize < 0) {
throw new ArgumentOutOfRangeException("newSize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
Contract.Ensures(Contract.ValueAtReturn(out array) != null);
Contract.Ensures(Contract.ValueAtReturn(out array).Length == newSize);
Contract.EndContractBlock();
T[] larray = array;
if (larray == null) {
array = new T[newSize];
return;
}
if (larray.Length != newSize) {
T[] newArray = new T[newSize];
Array.Copy(larray, 0, newArray, 0, larray.Length > newSize? newSize : larray.Length);
array = newArray;
}
}
}
This is my first question here so I hope I'm doing right.
I have to create a List of array of integer:
List<int[]> finalList = new List<int[]>();
in order to store all the combinations of K elements with N numbers.
For example:
N=5, K=2 => {1,2},{1,3},{1,4},...
Everything is all right but I want to avoid the repetitions of the same combination in the list({1,2} and {2,1} for example). So before adding the tmpArray (where I temporally store the new combination) in the list, I want to check if it's already stored.
Here it's what I'm doing:
create the tmpArray with the next combination (OK)
sort tmpArray (OK)
check if the List already contains tmpArray with the following code:
if (!finalList.Contains(tmpArray))
finalList.Add(tmpArray);
but it doesn't work. Can anyone help me with this issue?
Array is a reference type - your Contains query will not do what you want (compare all members in order).
You may use something like this:
if (!finalList.Any(x => x.SequenceEqual(tmpArray))
{
finalList.Add(tmpArray);
}
(Make sure you add a using System.Linq to the top of your file)
I suggest you learn more about value vs. reference types, Linq and C# data structure fundamentals. While above query should work it will be slow - O(n*m) where n = number of arrays in finalList and m length of each array.
For larger arrays some precomputing (e.g. a hashcode for each of the arrays) that allows you a faster comparison might be beneficial.
If I remember correctly, contains will either check the value for value data types or it will check the address for object types. An array is an object type, so the contains is only checking if the address in memory is stored in your list. You'll have to check each item in this list and perform some type of algorithm to check that the values of the array are in the list.
Linq, Lambda, or brute force checking comes to mind.
BrokenGlass gives a good suggestion with Linq and Lambda.
Brute Force:
bool itemExists = true;
foreach (int[] ints in finalList)
{
if (ints.Length != tmpArray.Length)
{
itemExists = false;
break;
}
else
{
// Compare each element
for (int i = 0; i < tmpArray.Length; i++)
{
if (ints[i] != tmpArray[i])
{
itemExists = false;
break;
}
}
// Have to check to break from the foreach loop
if (itemExists == false)
{
break;
}
}
}
if (itemExists == false)
{
finalList.add(tmpArray);
}
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.
In C++, we can set a range of values of an array(and other similar containers) using fill.
For example,
fill(number, number+n,10);
The above code will set the first n values of the array number with the value 10.
What is the closest C# equivalent to this.
There's no equivalent method but there are many ways to write similar code
Methods from the Linq-to-Objects classes can create sequences that you can use to initialize lists but this is very different from how things in C++ actually occur.
new List<char>(Enumerable.Repeat('A', 10));
new List<int>(Enumerable.Range(1, 10));
C++ can accomplish these things more generally thanks to how C++ templates work, and while simple type constraints in C# help, they do not offer the same flexibility.
I'm not sure one exists, but you can code your own easily:
void Fill<T>(T[] array, int start, int count, T value)
{
for (int i = start, j = 0; j < count; i++, j++)
array[i] = value;
}
Obviously missing parameter checking, but you get the drill.
There is no direct equivalent, but you can do it in two steps. First use Enumerable.Repeat to create an array with the same value in each element. Then copy that over the destination array:
var t = Enumerable.Repeat(value, count).ToArray();
Array.Copy(t, 0, dest, destStartIndex, count);
For other destination containers there is a lack of an equivalent to Array.Copy, but it is easy to add these as destinations, eg:
static void Overwrite<T>(this List<T> dest, IEnumerable<T> source, int destOffset) {
int pos = destOffset;
foreach (var val in source) {
// Could treat this as an error, or have explicit count
if (pos = dest.Length) { return; }
dest[pos++] = val;
}
}