2

I noticed some strange behavior when using a combination of ToList() and ToArray() in C# (using the .NET 4.5.2 famework).

Given the following test program:

int[] array = { 5, 1, -10, 667, 4 };
SorteerBib<int>.SelectionSort(array, Comparer<int>.Default);
Console.Out.WriteLine("Result - WRONG!");
for (int i = 0; i < array.Length; i++)
{
    Console.Out.Write(array[i] + " ");
    Console.Out.WriteLine();
}
Console.ReadKey();

The SorteerBib class consists of 2 methods:

class SorteerBib<T>
{
    public static IList<T> SelectionSort(IList<T> list, IComparer<T> comparer)
    {
        for (int i = 0; i < list.Count - 1; i++)
        {
            int minIndex = i;
            for (int j = i + 1; j < list.Count; j++)
            {
                if (comparer.Compare(list[j], list[minIndex]) < 0)
                {
                    minIndex = j;
                }
            }
            T temp = list[i];
            list[i] = list[minIndex];
            list[minIndex] = temp;
        }

        Console.Out.WriteLine("Result SelectionSort IList - OK");
        for (int i = 0; i < list.Count; i++)
        {
            Console.Out.Write(list[i]+" ");
            Console.Out.WriteLine();
        }
        return list;
    }

    public static void SelectionSort(T[] array, IComparer<T> comparer)
    {
        // DOES NOT WORK, WHY?
        array = ((SelectionSort(array.ToList(), comparer)).ToArray());

        Console.Out.WriteLine("Result SelectionSort Array - OK");
        for (int i = 0; i < array.Length; i++)
        {
            Console.Out.Write(array[i] + " ");
            Console.Out.WriteLine();
        }
    }
}

The error lies within the first line of the second method:

array = ((SelectionSort(array.ToList(), comparer)).ToArray());

Within the void method, the array is sorted after this line, but once we return to the main program the sorting is gone.

Replacing this line with the following lines however fixes this issue:

IList<T> temp = SelectionSort(array.ToList<T>(), comparer);
for (int i = 0; i < array.Length; i++) {
    array[i] = temp[i];
}

Can anyone explain this unpredictable behavior? Many thanks in advance!

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
PjM
  • 33
  • 2
  • 3
    There's no unpredictable behavior, pass the array as byref, then it will work, the second approach works because you're replacing elements in the array, not the array itself. – Gusman Oct 21 '16 at 12:03
  • Possible duplicate of [ToList()-- Does it Create a New List?](http://stackoverflow.com/questions/2774099/tolist-does-it-create-a-new-list) – Juan Oct 21 '16 at 12:03
  • 1
    FYI arrays implement `IList`, so no need for the second method or calling `ToList` when passing an array to the first one. – juharr Oct 21 '16 at 12:07
  • Agree with @Gusman, [this](http://stackoverflow.com/a/186907/4045532) explains why. – Corporalis Oct 21 '16 at 12:07

1 Answers1

0

You are passing the array without the ref keyword and then changing it's reference by doing:

array = ((SelectionSort(array.ToList(), comparer)).ToArray());

Since the ref keyword is not used, the change applies only in the function.

The fix will be to add the ref keyword:

public static void SelectionSort(ref T[] array, IComparer<T> comparer)

BTW a better approach will be to sort an ICollection<T> or an IEnumerable<T> instead.

Amir Popovich
  • 29,350
  • 9
  • 53
  • 99