In the C# programming language, how do I pass a row of a multi-dimensional array? For example, suppose I have the following:
int[,] foo;
foo = new int[6,4];
int[] least;
least = new int[6];
for(int i = 0; i < 6; i++)
{
least[i] = FindLeast(ref foo[i]); //How do I pass the ith row of foo???
}
Also, could anyone explain to me the benefit of having rectangular and jagged arrays in C#? Does this occur in other popular programming languages? (Java?)
Thanks for all the help!
You can't pass a row of a rectangular array, you have to use a jagged array (an array of arrays):
int[][] foo = new int[6][];
for(int i = 0; i < 6; i++)
foo[i] = new int[4];
int[] least = new int[6];
for(int i = 0; i < 6; i++)
least[i] = FindLeast(foo[i]);
EDIT
If you find it so annoying to use a jagged array and desperately need a rectangular one, a simple trick will save you:
int FindLeast(int[,] rectangularArray, int row)
You don't, with a rectangular array like that. It's a single object.
Instead, you'd need to use a jagged array, like this:
// Note: new int[6][4] will not compile
int[][] foo = new int[6][];
for (int i = 0; i < foo.Length; i++) {
foo[i] = new int[4];
}
Then you can pass each "sub"-array:
int[] least = new int[foo.Length];
for(int i = 0; i < 6; i++)
{
least[i] = FindLeast(foo[i]);
}
Note that there's no need to pass foo[i] by reference1, and also it's a good idea to assign local variables values at the point of declaration, when you can. (It makes your code more compact and simpler to understand.)
1 If you're not sure about this, you might want to read my article on parameter passing in C#.
Update: As Jon Skeet rightly points out, this does not provide a reference to the row, but rather creates a new copy. If your code needs to change a row, this method doesn't work. I have renamed the method to make this clear.
Update 2: If you want to be able to edit the fields, and have the changes happen to the parent array, too, you can use the wrapper I provide in this library I maed. The resulting row foo.Row(i) is not an array, but instead implements IList, so if you need to pass an array this is not a solution, either.
This extension method will allow you to query a multi-dimensional array for rows. It should be noted that this is computationally heavy (not efficient) and if it is possible you should use a jagged array for these situations. If, however, you find yourself in a situation where you cannot use a jagged array, this might be useful.
public static T[] CopyRow<T>(this T[,] arr, int row)
{
if (row > arr.GetLength(0))
throw new ArgumentOutOfRangeException("No such row in array.", "row");
var result = new T[arr.GetLength(1)];
for (int i = 0; i < result.Length; i++)
{
result[i] = arr[row, i];
}
return result;
}
Your code can now be rewritten:
int[,] foo;
foo = new int[6,4];
int[] least;
least = new int[6];
for(int i = 0; i < 6; i++)
{
least[i] = FindLeast(ref foo.CopyRow(i));
}
Related
I'm learning C# and I have created a code to add random numbers to a List using a for loop.
class Program
{
static void Main(string[] args)
{
Random numberGen = new Random();
List<int> randomNum = new List<int>();
for (int i = 0; i < 10; i++)
{
randomNum.Add(numberGen.Next(1, 100));
}
for (int i = 0; i < randomNum.Count; i++)
{
Console.WriteLine(randomNum[i]);
}
Console.ReadKey();
}
}
I want to know if there is a way to add random numbers to an array with a similar method?
The size of an array is fixed at the time of creation, so you can't add to an array; you can, however: create a new array that is bigger, copy the old data, and then append the new value(s) - Array.Resize does the first two steps - but: this is pretty expensive, which is why you usually use a List<T> or similar for this scenario. A List<T> maintains an oversized array in the background, so that it only has to resize and copy the underlying array occasionally (essentially, it doubles the size every time it gets full, so you get something approximating O(Log2(N)) overhead due to growth).
You could just assign to the relevant index directly, but note you'll have to initialize the array to the required size (as opposed to a List that can grow dynamically):
int[] randomNum = new int[10];
for (int i = 0; i < randomNum.Length; i++)
{
randomNum[i] = numberGen.Next(1, 100);
}
Use a List<T>, thats is the scenario it was precisely designed for. Once you've finished adding elements to it, if you need an array then simply call ToArray():
var myList = new List<int>();
//add random number of random numbers
var myArray = myList.ToArray();
I am working with Arrays and conditionals statements, little lost right now and was hoping for some input.
So, I created two Arrays
int[] one = new int[] {
4160414, 6610574, 2864453, 9352227, -4750937, -3132620, 2208017,
-2226227, -8415856, -9834062, -3401569, 7581671, 8068562, 7520435,
-9277044, -7821114, -3095212, 966785, 6873349, -8441152, -7015683,
-6588326, -282013, 4051534, 9930123, -3093234 };
int[] two = new int[] {
1099626, 6083415, 8083888, -8210392, 2665304, -8710738, -8708241,
8859200, -1255323, 5604634, 2921294, -7260228, 7261646, 1137004,
5805162, 4883369, 8789460, 9769240, 319012, -7877588, -1573772,
5192333, 1185446, 1302131, 4217472, -3471445};
My next step what i was thinking is i am going to have to loop through each array
for (int i = 0; i < one.Length; i++)
{
int xValue = one[i];
for (int j = 0; j < two.Length; j++)
{
int yValue = two[j];
}
}
Now that i have the index of each Array i need to check wether the index of xValue is less than the index of yValue
if (xValue < yValue)
{
// dO SOMETHING HERE
}
if (yValue < xValue)
{
// Do Something HERE
}
Where i am getting confused at, is with C# from my understanding you can not push new values into an Array, it needs to be a new instance of the array and copy?
So i tried doing
if (xValue < yValue)
{
Array.Copy(one, x, 13);
}
if (yValue < xValue)
{
Array.Copy(two, x, 13)
}
Both Arrays have 26 values, so a new array of 13 would need to be created to insert the checked value, but Array.Copy seems to not be working getting an array out of bounds check lower bounds.
I'm just confused on checking the values of both arrays at their index, then grabbing the smallest value of the checked values then taking that small value and inserting it into a new array, then use a foreach-loop to iterate over it and print the values to the console. FacePalm
You can use LINQ's Zip to achieve this:
int[] smallest = one.Zip(two, (o, t) => Math.Min(o,t)).ToArray();
Essentially, Zip will provide both items to the lambda expression, allowing you to combine them how you see fit. In this case, we just choose the minimum and return it.
Try it online
Basically, you need to define the size of the new array when you declare it. Make it the same size as one. Then add the smallest item from one or two on each iteration by comparing the items in each array at index i.
int[] smallest = new int[one.Length];
for (int i = 0; i < one.Length; i++)
{
if (one[i] < two[i])
{
smallest[i] = one[i];
}
else
{
smallest[i] = two[i];
}
}
There are may operations on arrays that do not depend on the rank of an array. Iterators are also not always a suitable solution. Given the array
double[,] myarray = new double[10,5];
it would be desirable to realize the following workflow:
Reshape an array of Rank>1 to a linear array with rank=1 with the same number of elements. This should happen in place to be runtime efficient. Copying is not allowed.
Pass reshaped array to a method defined for Rank=1 arrays only. e.g. Array.copy()
Reshape result array to original rank and dimensions.
There is a similar question on this topic: How to reshape array in c#. The solutions there use memory copy operation with BlockCopy().
My question are:
Can this kind of reshaping be realized without memory copy? Or even in a temporary way like creating a new view on the data?
There wording to this is a little tough, yet surely pointers unsafe and fixed would work. No memory copy, direct access, add pepper and salt to taste
The CLR just wont let you cast an array like you want, any other method you can think of will require allocating a new array and copy (which mind you can be lightening fast). The only other possibly way to so this is to use fixed, which will give you contiguous 1 dimensional array.
unsafe public static void SomeMethod(int* p, int size)
{
for (var i = 0; i < 4; i++)
{
//Perform any linear operation
*(p + i) *= 10;
}
}
...
var someArray = new int[2,2];
someArray[0, 0] = 1;
someArray[0,1] = 2;
someArray[1, 0] = 3;
someArray[1, 1] = 4;
//Reshape an array to a linear array
fixed (int* p = someArray)
{
SomeMethod(p, 4);
}
//Reshape result array to original rank and dimensions.
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
Console.WriteLine(someArray[i, j]);
}
}
Output
10
20
30
40
Problem is that after Randomize func, array forcombo equals random_for_combo, but I do not equate them anywhere. Please help.
private void button1_Click(object sender, EventArgs e)
{
string sub = "1#2#3#4#5#6#7#8#9#10";
string[] split = sub.Split('#');
string[] forcombo = new string[split.Length / 2];
int s = 0;
for (int j = 1; j <= split.Length - 1; j += 2)
{
forcombo[s] = split[j];
s++;
}
string[] random_for_combo = new string[forcombo.Length];
random_for_combo = forcombo;
MessageBox.Show(forcombo[0] + forcombo[1] + forcombo[2] + forcombo[3] + forcombo[4], "Before random");
random_for_combo = RandomizeStrings(random_for_combo);
MessageBox.Show(forcombo[0]+forcombo[1]+forcombo[2]+forcombo[3]+forcombo[4], "After random");
}
public static string[] RandomizeStrings(string[] arr)
{
ArrayList l1 = new ArrayList(arr.Length);
ArrayList l2 = new ArrayList(arr.Length);
foreach (object k in arr)
{
l1.Add(k.ToString());
}
while (l1.Count > 0)
{
Random rnd = new Random();
int rand = rnd.Next(l1.Count);
l2.Add(l1[rand]);
l1.RemoveAt(rand);
Thread.Sleep(rnd.Next(50));
}
for (int i = 0; i < l2.Count; i++)
{
arr[i] = l2[i].ToString();
}
return arr;
}
Some helpless info to complete question..
There's a couple of problems with this code:
You're copying the reference from one array variable into another:
random_for_combo = forcombo;
This does not make the two variables contain two arrays that contain the same values, the two values now refer to the same one array in memory. Change one, and it will appear the other one changed as well. Think of the two variables as postit notes with the address of a house on them, the same address. If you go to the house and rearrange the furniture, "both houses" will appear to be changed. There is only one house however.
When you pass the array to the randomize method, you're passing a reference to the array, not a copy of the array, which means that if you change the contents of the array, you're not working on a copy, you're working on the original. This means that the array you get passed, and the array you return, is the same one array in memory
Probably not the source of the bugs in your question, but you shouldn't construct new Random objects every time you use it in a loop, instead construct it once and reuse, otherwise you risk getting back just a few distinct values.
Lastly, if your gut reaction is "this is a bug in visual studio or C#", then it almost never is, always work on the presumption that it is your own code that is faulty. By "almost never" I would say that the chance of you hitting a bug in C# or Visual Studio by chance is none.
To make a new array with the same contents of another, you have a few options:
Explicitly make an array and copy over the elements one by one:
random_for_combo = new string[forcombo.Length];
for (int i = 0; i < forcombo.Length; i++)
random_for_combo[i] = forcombo[i];
Use Array.Copy instead of the for-loop:
random_for_combo = new string[forcombo.Length];
Array.Copy(forcombo, random_for_combo, forcombo.Length);
Use the new Linq ToArray extension method:
random_for_combo = forcombo.ToArray();
Note that even though this looks like a no-op (since forcombo is an array), you'll actually get a new array with the same contents.
but you did here :
random_for_combo = forcombo;
you set random_for_combo so it point to forcombo.
if you want to use the original array than you need to copy it to new array
something like this (instead of the above line)
string[] random_for_combo = new string[forcombo.Length];
for (int i = 0; i < forcombo.Length; i++)
{
random_for_combo[i] = forcombo[i];
}
I initialized an Array as
Double[][] myarr = Enumerable.Repeat(new double[12], 13).ToArray();
Then in a loop i am incrementing values like
myarr[0][0]++;
This causes all values like myarr[1][0], myarr[2][0], myarr[3][0] ..... myarr[12][0] to increment by one.
This problem is not occurring when using a for loop (0-12) i am initializing like
myarr[i] = new double[12];
Why is this so?
Other answers have explained the problem. The solution is to create a new array on each iteration, e.g.
double[][] myarr = Enumerable.Range(0, 13)
.Select(ignored => new double[12])
.ToArray();
It's because new double[12] creates a single array object in memory - Enumerable.Repeat is simply providing you with multiple references to that array.
This is expected behavior - array is a referebce type. You are creating a jagged array i.e. array of arrays. All elements of your outer array references the same inside array i.e the first argument of Repeat call, so changes in the inside array will be reflected at on indices (because all indices refer to the same array).
With new double[12] you are creating reference to array of doubles, and then you repeate the reference 12 times, so myarr[0..n] will have reference to one memory region.
You can use the folowing method to resolve thw issue
static T[][] CreateArray<T>(int rows, int cols)
{
T[][] array = new T[rows][];
for (int i = 0; i < array.GetLength(0); i++)
array[i] = new T[cols];
return array;
}
Or with custom Repeat method which calls action every step:
public static IEnumerable<TResult> RepeatAction<TResult>(Action<TResult> elementAction, int count)
{
for (int i = 0; i < count; i++)
{
yield return elementAction();
}
yield break;
}
usage
RepeatAction(()=>new double[12], 12);
Arrays are references. In the Repeat call you create one array and assign its reference 12 times. In your loop however you create 12 distinct arrays.
Repeat() basically just capture and yields the same element multiple times, so you got multiple references to the same object instance in the memory.
This is how Repeat() is implemented:
private static IEnumerable<TResult> RepeatIterator<TResult>(TResult element, int count)
{
for (int i = 0; i < count; i++)
{
yield return element;
}
yield break;
}