5

Working on MergeSort in Java:

public void mergeSort(int[] A)
{
     if (A.length > 1)
     {
         int q = A.length/2;
         int[] leftArray = Arrays.copyOfRange(A, 0, q);
         int[] rightArray = Arrays.copyOfRange(A,q,A.length);
         mergeSort(leftArray);
         mergeSort(rightArray);
         merge(A,leftArray,rightArray);
     }
}

The recursion in the code above works well in Java.

So for curiosity I want to convert function Arrays.copyOfRange from java to c#. Array.copy in C# takes five arguments. Do you know any simpler function in c# do get certain elements of the array starting at position x to y (like java).

In c# I coded the above method like this:

public void mergeSort(int[] A)
{
    if (A.Length > 1)
    {
        int q = A.Length / 2;
        int[] leftArray = new int[q];
        int[] rightArray = new int[A.Length];
        for (int i = 0; i < q; i++)
        {
            leftArray[i] = A[i];
            Console.WriteLine(leftArray[i]);
        }

        for (int i = q; i < A.Length; i++)
        {
            rightArray[i] = A[i];
            Console.WriteLine(rightArray[i]);
        }
        Console.ReadKey();

        mergeSort(leftArray);
        mergeSort(rightArray);
        merge(A, leftArray, rightArray);
    }
}

As you can see I have replaced Arrays.copyOfRange functions in Java with two loops in c# and this works in c# without recursion. However calling mergeSort(leftArray) and mergeSort(rightArray) it prints this in c#:

Process is terminated due to StackOverflowException!!

Any better idea on how to get certain elements in c#?

3
  • msdn.microsoft.com/en-us/library/… Commented Jan 21, 2014 at 21:52
  • 1
    Why is this question downvoted? This is precisely the info I was looking for Commented Sep 12, 2014 at 8:50
  • 1
    I also am baffled by the downvotes. Perhaps the downvoters are not familiar enough with both java and C# to grasp that the java function copyOfRange has no direct equivalent in C#, in the sense that C# requires a separate action to create an array, before performing Array.Copy. This is why a newcomer to C# may struggle a bit before seeing a good equivalent. IMHO this question is very useful to some beginners. Commented Sep 23, 2015 at 8:51

2 Answers 2

12

The problem is the ported array copy is not doing the same thing.

Given an input of [a,b,c,d,e,f] the Java code is creating two arrays, [a,b,c] and [d,e,f] while the C# port is creating two arrays, [a,b,c] and [0,0,0,d,e,f]. Notably,

  • The new right array is the size of A (new int[A.Length]). This is what causes the StackOverflowException as the termination case is never reached, and;
  • The new right array is only assigned values starting at the q index, which is the half-way index.

Consider this replacement method using Array.Copy - a method with the same signature can be used as a drop in replacement in ported code, as long as what's inside the method has the same effect as the original.

int[] copyOfRange (int[] src, int start, int end) {
    int len = end - start;
    int[] dest = new int[len];
    Array.Copy(src, start, dest, 0, len);
    return dest;
}

Or, a version that does it with a loop but without the issue in the original port. Another reason to use discreet functions - it makes the task easy to see and reason about. Being able to also eliminate duplicate code doesn't hurt.

int[] copyOfRange (int[] src, int start, int end) {
    int len = end - start;
    int[] dest = new int[len];
    // note i is always from 0
    for (int i = 0; i < len; i++)
    {
        dest[i] = src[start + i]; // so 0..n = 0+x..n+x
    }
    return dest;
}

If you're lazy like me, the code could also be trivially written using LINQ.

int[] leftArray = A.Take(q).ToArray();
int[] rightArray = A.Skip(q).ToArray();
Sign up to request clarification or add additional context in comments.

5 Comments

calling your first method: int[] copyOfRange (int[] src, int start, int len) with parameters: A, 0, q prints the following error: Source array was not long enough. Check srcIndex and length, and the array's lower bounds.
@Milot25 That was my original version, but (due to an oversight) it didn't match the Arrays.copyOfRange contract - oops. I've updated the code in the post for both functions to take in an end parameter (from which len is derived) so that can actually be used as a drop-in replacement for Java's Arrays.copyOfRange.
Your function is working. However I think the recursive method is causing something wrong in C#. Given an array: int[] a = {6, 3, 8, 5, 1, 9, 7, 3, 2, 4}; it prints only 3,6 whereas in Java: 1,2,3,4,5,6,7,8,9
@Milot25 Maybe the merge method is wrong? The input array and the output array must be the same size - if not, then elements were lost. I am very suspicious of this reported result as the final output array is the same as the input array (and thus even if there are bunch of 0 elements, it should be the same length).
I realize I have made some semantic mistake in merge algorithm implementation. Now everything works fine. Thanks very very much Sir.
0

Now in modern C# there is a simple solution for this:

string[] cuttedArray = array[2..6] // from second element to sixth element exclusive

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.