I have this as Main
int[] M ={ 10, 2, 30, 4, 50, 6, 7, 80 };
MyMath.Reverse(M);
for (int i = 0; i < M.Length; i++)
Console.WriteLine(M[i].ToString() + ", ");
After I created the class MyMath I made the Reverse method
public int Reverse(Array M)
{
int len = M.Length;
for (int i = 0; i < len / 2; i++)
{
int temp = M[i]; M[i] = M[len - i - 1]; M[len - i - 1] = temp;
}
}
but I'm sure it's wrong because it's not working :-) so do you have a different code to write in the reverse method?
note: I don't want to use the built in Reverse in the Array class
yes guys when i used the built in reverse method i got this error
Process is terminated due to StackOverflowException.
thats after i wrote the method as
public static int Reverse(Array M)
{
return Reverse(M);
}
So then I tried to create my own reverse method and there i got stuck
Working from your
public static int Reverse(Array M)
{
return Reverse(M);
}
You have 2 problems.
Reverse(M) looks like the same function that you're in, so you're calling your new function, which calls itself, which calls itself, etc., resulting in the stack overflow. Change to return Array.Reverse(M);
Array.Reverse returns a void, so if you need to return an int (not sure what it's supposed to be here) you'll need to supply your own. Or change your Reverse function to be void.
To fix your problem, change your method to:
// the built-in returns void, so that needed to be changed...
public static void Reverse(Array M)
{
Array.Reverse(M); // you forgot to reference the Array class in yours
}
There, no Stack Overflow problems.
It makes next to no sense to not use Array.Reverse.
But if you really want to do it, ONE option could be to duplicate the array into a Stack, although I do not believe that this is very fast (but I have not profiled it either):
private void Whatever()
{
int[] M = { 10, 2, 30, 4, 50, 6, 7, 80 };
ReverseArray(ref M);
}
private void ReverseArray(ref int[] input)
{
Stack<int> tmp = new Stack<int>();
foreach (int i in input)
{
tmp.Push(i);
}
input = tmp.ToArray();
}
You need to pass you array as a reference. In C#, you do that by using the keyword 'ref' when declaring your parameters.
What you are currently doing is basically reversing a copy of your array which is never passed back to the caller.
Related
I'm making a C# script in Unity. My intention is to create a class Scenario, create classes representing different scenarios, which would then be stored in an array scenarioListAll.
A (simplified) version of the code is as follows:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OverallManager2 : MonoBehaviour
{
public static object[] scenarioListAll = new object[40];
public class Scenario
{
public string scenarioDesc;
public bool surprise; // The 'surprise' bool I want to reference is defined here
public string surpriseType;
public int[] leftOption;
public int[] rightOption;
public int scenarioNumber;
public Scenario(string st, bool sp, int[] l, int[] r, int n)
{
scenarioDesc = st;
surprise = sp;
leftOption = l;
rightOption = r;
scenarioNumber = n;
}
// I haven't used this, but I'm not sure if this matters so I'm including this too
public Scenario(string st, bool sp, string spt, int[] l, int[] r, int n)
{
scenarioDesc = st;
surprise = sp;
surpriseType = spt;
leftOption = l;
rightOption = r;
scenarioNumber = n;
}
}
public static int[] getArray(int a, int b, int c, int d, int e, int f)
{
int[] arr = new int[6] {a, b, c, d, e, f};
return arr;
}
// Storing scenarios, am looking for the bool (2nd position)
public Scenario s1 = new Scenario("Test1", false, getArray(1, 1, 1, 1, 1, 1), getArray(1, 1, 1, 1, 1, 1), 1);
public Scenario s2 = new Scenario("Test2", true, getArray(1, 1, 1, 1, 1, 1), getArray(1, 1, 1, 1, 1, 1), 2);
public Scenario s3 = new Scenario("Test3", false, getArray(1, 1, 1, 1, 1, 1), getArray(1, 1, 1, 1, 1, 1), 3);
void Awake()
{
// Store scenarios in object array
scenarioListAll[0] = s1;
scenarioListAll[1] = s2;
scenarioListAll[2] = s3;
for(int i = 0; i < 40; i++)
{
object temp = scenarioListAll[i]; // Trying to extract the object stored in the array in a temp object
bool surpriseCheck = temp.surprise; // I am having problems with this line
if(surpriseCheck == true)
{
// Do something
}
}
}
// Ignoring start and update since they're irrelevant in this context
}
What I would like to do is to check whether the surprise element within a newly defined scenario (e.g. s1) is true. To do that, I was planning to extract the scenario stored in the array scenarioListAll, and then extract the surprise component from there. However, I'm couldn't figure out how to do this (e.g. in the code shown above, it returns Compiler Error CS1061).
I don't think I was able to find any documentation on this either, but I might not have understood something. I'm learning on my own so please bear with my poor knowledge/presentation.
Thank you for your time. Your help is much appreciated.
You are having a compilation issue due to the fact that the c# compiler doesn't know that temp is a Scenario since you declared it as "object". If you want to loop through the scenarios and check to see if they are a surprise you can use something like this:
foreach(Scenario temp in scenarioListAll)
{
bool surpriseCheck = temp.surprise;
if(surpriseCheck == true)
{
// Do something
}
}
Another way of accomplishing the same task with more control over the iteration would be:
for(int i = 0; i < scenarioListAll.Length; i++)
{
Scenario temp = scenarioListAll[i];
bool surpriseCheck = temp.surprise;
if(surpriseCheck == true)
{
// Do something
}
}
The benefit of the first version is that you don't have to worry about overrunning the bounds of the array. As Mike added below you could also use var to have the compiler fill in the type for you.
It's sometimes easiest to allow the compiler to determine the type of a variable for us.
In your case, you've specified that the variable temp will be of type object. Now, that's fine, but while a Scenario derives from object, and object is the lowest level class in the .Net environment, and is not a Scenario.
The var keyword doesn't mean that the declared type is of a "variable" type, instead it's telling the compiler just to "fill in" the correct type, based on the action you're taking. So, to put this in to action in your case, you could do this instead:
for( var i = 0; i < 40; i++ ) // notice the use of var here as well
{
var scenario = scenarioListAll[i]; // renamed temp to scenario
// var surpriseCheck = scenario .surprise; // var used but line not required
if( scenario.surprise )
{
// Do something
}
}
I went overboard there to demonstrate that the compiler is quite happy with the var keyword just about wherever you'd specify a data type as a type for a variable. Obviously not when you're trying to cast types, and there ARE sometimes where you'd want to specify the exact type you're trying to instantiate.
In your case, your next issue will be that you've defined the array as having 40 object elements, but you've then only instantiated 3 Scenario elements (which is valid, but probably not quite what you want overall). So your code, as it stands, is going to NullReference error out. You'll be able to avoid that, with a small modification, so your amended code could look like this, to include some type checks:
for( var i = 0; i < scenarioListAll.Length; i++ )
{
// First, check to see if the object in the array cell is a Scenario.
// If the item in the cell is a Scenario, check to see if surprise is set.
if ( scenarioListAll[i] is Scenario scenario && scenario.surprise )
{
// Do something
}
}
for more information on the is keyword, check the Microsoft Docs here.
This is my first question on the site and I am sure I'll find my answer here.
For school, I was trying to do some basic C# coding for a challenge that was given to us.
Here is the problem:
Normally when I pass a value through a method I don't run into issues. Like so:
static void Main(string[] args)
{
// Declare Integer
int originalInt = 20;
// Call the Method
int multipliedInt = Multiplication(originalInt);
// Prompt
Console.WriteLine("Original: {0} Modified: {1}", originalInt, multipliedInt);
}
// Method
static public int Multiplication(int original)
{
// Quik Maffs
int modifiedValue = original * 2;
return modifiedValue;
}
The above example works just fine. The original value is 20 and the modified value is 40.
However, this changes when I attempt to do that with an array:
static void Main(string[] args)
{
// Declare Original Array
int[] originalArray = new int[] {1, 4, 6, 8, 12};
// Call Method
int[] multipliedArray = Multiplication(originalArray);
// Prompt
Console.WriteLine("Original: [{0}], Multiplied: [{1}]", String.Join(", ", originalArray), String.Join(", ", multipliedArray));
}
// Method
static public int[] Multiplication(int[] original)
{
// New Int
int[] modified = original;
// Loop
for (int i = 0; i < modified.Length; i++)
{
modified[i] *= 2;
}
return modified;
}
The code above returned the modified value twice. It seems like it modifies the original value as well.
Any idea why this is happening?
int is a value type. When you pass a value type to a method, you pass a copy of the value.
Arrays are reference types. When you pass a reference type to a method, you pass a copy of the reference... but both the copy and original still refer to the same object.
Now it seems you may have understood this much, because of this code:
(This is why I re-opened the question... the stock ref-vs-value answer wasn't gonna cut it here)
int[] modified = original;
However, the other thing that happens with reference types is assignments also only copy the reference. So modified and original in that snippet again refer to the same array object.
To fix this, you need to make an actual deep copy of the array. There are several ways to do this. I would tend to write the method this way:
static public IEnumerable<int> Multiplication(IEnumerable<int> original)
{
return original.Select(i => i * 2);
}
...and append a .ToArray() at the end of the method call if and only if I really need a full array (hint: very often it turns out you don't), like this:
int[] multipliedArray = Multiplication(originalArray).ToArray();
or like this:
var multipliedArray = Multiplication(originalArray);
But I understand there are a number of things here that aren't very familiar to a beginner. You might try something more like this:
static public int[] Multiplication(int[] original)
{
int[] modifed = new int[original.Length];
for (int i = 0; i < original.Length; i++)
{
modified[i] = original[i] * 2;
}
return modified;
}
I am trying to implement a generic Mergesort algorithm in C#, but I am having difficulty with the Constraints. I have searched many references but I can't find any that are implementing the algorithm like I am.
MergeSort algorithm in C#
Generic Implementation of Sorting Algorithms
Anyways, I am trying to provide an implementation that only allows the user to Mergesort a dataset that inherits from the IComparable interface.
Below is what I have so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SortUtil
{
class Program
{
static void Main(string[] args)
{
List<int> testList = new List<int> { 1, 5, 2, 7, 3, 9, 4, 6 };
Mergesort.mergeSort<int>(testList); // Compiler Error at this Line.
}
}
class Mergesort
{
public static void mergeSort<T>(ref List<T> inputData)
where T: IComparable<T>
{
mergeSort(ref inputData, 0, inputData.Count - 1);
}
private static void mergeSort<T>(ref List<T> inputData, int firstIndex, int lastIndex)
where T: IComparable<T>
{
// If the firstIndex is greater than the lastIndex then the recursion
// has divided the problem into a single item. Return back up the call
// stack.
if (firstIndex >= lastIndex)
return;
int midIndex = (firstIndex + lastIndex) / 2;
// Recursively divide the first and second halves of the inputData into
// its two seperate parts.
mergeSort(ref inputData, firstIndex, midIndex);
mergeSort(ref inputData, midIndex + 1, lastIndex);
// Merge the two remaining halves after dividing them in half.
merge(ref inputData, firstIndex, midIndex, lastIndex);
}
private static void merge<T>(ref List<T> inputData, int firstIndex, int midIndex, int lastIndex)
where T: IComparable<T>
{
int currentLeft = firstIndex;
int currentRight = midIndex + 1;
T[] tempData = new T[(lastIndex - firstIndex) + 1];
int tempPos = 0;
// Check the items at the left most index of the two havles and compare
// them. Add the items in ascending order into the tempData array.
while (currentLeft <= midIndex && currentRight <= lastIndex)
if (inputData.ElementAt(currentLeft).CompareTo(inputData.ElementAt(currentRight)) < 0)
{
tempData[tempPos++] = inputData.ElementAt(currentLeft++);
}
else
{
tempData[tempPos++] = inputData.ElementAt(currentRight++);
}
// If there are any remaining items to be added to the tempData array,
// add them.
while (currentLeft <= midIndex)
{
tempData[tempPos++] = inputData.ElementAt(currentLeft++);
}
while (currentRight <= lastIndex)
{
tempData[tempPos++] = inputData.ElementAt(currentRight++);
}
// Now that the items have been sorted, copy them back into the inputData
// reference that was passed to this function.
tempPos = 0;
for (int i = firstIndex; i <= lastIndex; i++) {
inputData.Insert(firstIndex, tempData.ElementAt(tempPos));
}
}
}
}
My issue: I am getting a Compiler error in the Main method of the Program class; however, shouldn't I have to supply the mergeSort function the parametrized type when I call it statically?
I am getting the error "The best overloaded method match for... has some invalid arguments."
I would greatly appreciate any implementation suggestions and/or any way of correcting this error. Note, I am most comfortable in Java, and since C# doesn't directly support wildcards this approach is foreign to me. Any explanations on this would be appreciated as well.
You could remove ref from all of your parameters since you do not seem to be using its functionality.
Also you would not need to provide generic parameter type in most cases because the compiler will infer the type for you. So this should work (assuming you've removed ref from the parameters) in most cases:
Mergesort.mergeSort(testList);
Also List<T> and arrays have indexers so you can get at specific elements via inputData[index] instead of ElementAt. It's just less typing that way.
MergeSort reuires a ref parameter, so it needs the ref keyword. This should work:
Mergesort.mergeSort<int>(ref testList);
The ref keyword causes an argument to be passed by reference, not by
value. The effect of passing by reference is that any change to the
parameter in the method is reflected in the underlying argument
variable in the calling method. The value of a reference parameter is
always the same as the value of the underlying argument variable.
Is the C# code below the equivalent way of trying to achieve the same as the C++ code?
Is there any way to avoid the copy (while not sending the whole array to the function)?
C++
static void somefunction(double* v, int nb)
{
//something that will update v[0],v[1], ... v[nb-1]
}
double * myarray=new double[100];
somefunction(&myarray[10],5);
//...
delete [] myarray;
C#
static void somefunction(double[] v, int nb)
{
//something that will update v[0],v[1], ... v[nb-1]
}
double[] myarray=new double[100];
double[] temp_array=new double[5];
somefunction(temp_array,5);
temp_array.CopyTo(myarray,10);
Arrays are reference types. You are not sending the whole array to the function: you are sending a reference to the array.
If you want your function to update only part of that array, pass the start and end indices as parameters.
In C++, use std::vector, and iterator-pair.
And in C#, you could pass the entire array (which is a reference type) along with a pair of indices signifying begin and end.
C++ code should look like this:
void f(double *begin, double *end)
{
for ( ; begin < end; ++begin )
{
auto & value = *begin;
//etc
}
}
std::vector<double> v(100);
f(&v[10], &v[10] + 5);
That is idiomatic, and follows the Standard library philosophy!
And C# code should look like this:
void f(double[] v, int begin, int end)
{
for ( ; begin < end ; ++end )
{
//access v[begin]
//etc
}
}
double[] v =new double[100];
f(v, 10, 10 + 5);
This attempts to imitate C++ style. Nothing wrong with that. However, in C#, it is customary to pass the start index and the count, so you can do the following instead:
void f(double[] v, int startIndex, int count)
{
for (int i = 0 ; i < count ; ++i, ++startIndex)
{
//access v[startIndex]
//etc
}
}
double[] v =new double[100];
f(v, 10, 5); //note the difference here!
The second approach follows the .NET library philosophy. I would with this.
Hope that helps.
You could use an ArraySegment to specify the range of the array. You would still need to interrogate the Array, Count and Offset properties of the ArraySegment though. Still, it provides a convenient wrapper.
The alternative would be to write a full-blown IList wrapper for the array (or ICollection, or some other collection type).
I ran into what was to me an unexpected result when testing a simple ForEach extension method.
ForEach method
public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null) throw new ArgumentNullException("action");
foreach (T element in list)
{
action(element);
}
}
Test method
[TestMethod]
public void BasicForEachTest()
{
int[] numbers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
numbers.ForEach(num =>
{
num = 0;
});
Assert.AreEqual(0, numbers.Sum());
}
Why would numbers.Sum() be equal to 55 and not 0?
num is the copy of the value of the current element you are iterating over. So you are just changing the copy.
What you do is basically this:
foreach(int num in numbers)
{
num = 0;
}
Surely you do not expect this to change the content of the array?
Edit: What you want is this:
for (int i in numbers.Length)
{
numbers[i] = 0;
}
In your specific case you could maintain an index in your ForEach extension method and pass that as second argument to the action and then use it like this:
numbers.ForEachWithIndex((num, index) => numbers[index] = 0);
However in general: Creating Linq style extension methods which modify the collection they are applied to are bad style (IMO). If you write an extension method which cannot be applied to an IEnumerable<T> you should really think hard about it if you really need it (especially when you write with the intention of modifying the collection). You have not much to gain but much to loose (like unexpected side effects). I'm sure there are exceptions but I stick to that rule and it has served me well.
Because num is a copy.
It's as if you were doing this:
int i = numbers[0];
i = 0;
You wouldn't expect that to change numbers[0], would you?
Because int is a value type and is passed to your extension method as a value parameter. Thus a copy of numbers is passed to your ForEach method. The values stored in the numbers array that is initialized in the BasicForEachTest method are never modified.
Check this article by Jon Skeet to read more on value types and value parameters.
I am not claiming that the code in this answer is useful, but (it works and) I think it illustrates what you need in order to make your approach work. The argument must be marked ref. The BCL does not have a delegate type with ref, so just write your own (not inside any class):
public delegate void MyActionRef<T>(ref T arg);
With that, your method becomes:
public static void ForEach2<T>(this T[] list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Length; idx++)
{
actionRef(ref list[idx]);
}
}
Now, remember to use the ref keyword in your test method:
numbers.ForEach2((ref int num) =>
{
num = 0;
});
This works because it is OK to pass an array entry ByRef (ref).
If you want to extend IList<> instead, you have to do:
public static void ForEach3<T>(this IList<T> list, MyActionRef<T> actionRef)
{
if (actionRef == null)
throw new ArgumentNullException("actionRef");
for (int idx = 0; idx < list.Count; idx++)
{
var temp = list[idx];
actionRef(ref temp);
list[idx] = temp;
}
}
Hope this helps your understanding.
Note: I had to use for loops. In C#, in foreach (var x in Yyyy) { /* ... */ }, it is not allowed to assign to x (which includes passing x ByRef (with ref or out)) inside the loop body.