G
Guest
The implementation of the Sort() method on a System.Collections.ArrayList
object seems to have changed in v2.0. In particular, attempting to sort
partially sorted data is very slow. Maybe using QuickSort on already sorted
data will result in worst case performance, but v1.1 ArrayList.Sort() doesn't
display the same level of slowness, nor does List<string>.Sort().
I've included test code (console app) below to demonstrate the problem. It
creates an already sorted string array, adds an extra string to various
locations in the array, then calls Sort(). To run against v1.1, which
doesn't include the generic test, simply comment out the "#define CLR_V2".
I'm seeing this issue on all machines tested. Here is sample output:
*****************
*****************
Compiled with Framework Version: v1.1.4322
Sort Test: No extra string added
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' inserted at beginning
ArrayList: 0.0312476(s)
Sort Test: Extra string 'aaa' inserted at middle
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' added to end
ArrayList: 0.0624952(s)
*****************
Compiled with Framework Version: v2.0.50727
Sort Test: No extra string added
List<string>: 0.0624952(s)
ArrayList: 0.0312476(s)
Sort Test: Extra string 'aaa' inserted at beginning
List<string>: 0.0468714(s)
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' inserted at middle
List<string>: 0.0624952(s)
ArrayList: 5.7183108(s)
Sort Test: Extra string 'aaa' added to end
List<string>: 0.0468714(s)
ArrayList: 23.0138574(s)
*****************
*****************
Code:
(copy\paste over generated class in a Visual Studio Console Application
Project )
#define CLR_V2
using System;
using System.Collections;
class Program
{
enum IncludeExtraString
{
None,
FirstElement,
MiddleElement,
LastElement
}
static void Main(string[] args)
{
string extra = "aaa";
Console.WriteLine("Compiled with Framework Version: {0}",
System.Reflection.Assembly.GetExecutingAssembly().ImageRuntimeVersion);
Console.WriteLine();
Console.WriteLine("Sort Test:\tNo extra string added");
ArrayTest(IncludeExtraString.None, null);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' inserted at
beginning", extra);
ArrayTest(IncludeExtraString.FirstElement, extra);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' inserted at middle",
extra);
ArrayTest(IncludeExtraString.MiddleElement, extra);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' added to end", extra);
ArrayTest(IncludeExtraString.LastElement, extra);
}
static void ArrayTest(IncludeExtraString includeString, string extraString)
{
DateTime start, end;
string[] strArray = CreateArray(includeString, extraString);
#if CLR_V2
System.Collections.Generic.List<string> genericList =
new System.Collections.Generic.List<string>(strArray.Length);
genericList.AddRange(strArray);
start = DateTime.Now;
genericList.Sort();
end = DateTime.Now;
Console.WriteLine("List<string>:\t{0}(s)", ((TimeSpan)(end -
start)).TotalSeconds);
#endif
ArrayList arrayList = new ArrayList(strArray.Length);
arrayList.AddRange(strArray);
start = DateTime.Now;
arrayList.Sort();
end = DateTime.Now;
Console.WriteLine("ArrayList:\t{0}(s)", ((TimeSpan)(end -
start)).TotalSeconds);
}
static string[] CreateArray(IncludeExtraString includeString, string
extraString)
{
ArrayList list = new ArrayList();
char[] charString = new char[3];
for (int firstChar = 0; firstChar < 26; firstChar++)
{
charString[0] = Convert.ToChar('a' + firstChar);
for (int secondChar = 0; secondChar < 26; secondChar++)
{
charString[1] = Convert.ToChar('a' + secondChar);
for (int thirdChar = 0; thirdChar < 26; thirdChar++)
{
charString[2] = Convert.ToChar('a' + thirdChar);
list.Add(new string(charString));
}
}
}
switch (includeString)
{
case IncludeExtraString.FirstElement:
list.Insert(0, extraString);
break;
case IncludeExtraString.MiddleElement:
list.Insert(list.Count / 2, extraString);
break;
case IncludeExtraString.LastElement:
list.Add(extraString);
break;
}
return (string[])list.ToArray(typeof(string));
}
}
object seems to have changed in v2.0. In particular, attempting to sort
partially sorted data is very slow. Maybe using QuickSort on already sorted
data will result in worst case performance, but v1.1 ArrayList.Sort() doesn't
display the same level of slowness, nor does List<string>.Sort().
I've included test code (console app) below to demonstrate the problem. It
creates an already sorted string array, adds an extra string to various
locations in the array, then calls Sort(). To run against v1.1, which
doesn't include the generic test, simply comment out the "#define CLR_V2".
I'm seeing this issue on all machines tested. Here is sample output:
*****************
*****************
Compiled with Framework Version: v1.1.4322
Sort Test: No extra string added
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' inserted at beginning
ArrayList: 0.0312476(s)
Sort Test: Extra string 'aaa' inserted at middle
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' added to end
ArrayList: 0.0624952(s)
*****************
Compiled with Framework Version: v2.0.50727
Sort Test: No extra string added
List<string>: 0.0624952(s)
ArrayList: 0.0312476(s)
Sort Test: Extra string 'aaa' inserted at beginning
List<string>: 0.0468714(s)
ArrayList: 0.0468714(s)
Sort Test: Extra string 'aaa' inserted at middle
List<string>: 0.0624952(s)
ArrayList: 5.7183108(s)
Sort Test: Extra string 'aaa' added to end
List<string>: 0.0468714(s)
ArrayList: 23.0138574(s)
*****************
*****************
Code:
(copy\paste over generated class in a Visual Studio Console Application
Project )
#define CLR_V2
using System;
using System.Collections;
class Program
{
enum IncludeExtraString
{
None,
FirstElement,
MiddleElement,
LastElement
}
static void Main(string[] args)
{
string extra = "aaa";
Console.WriteLine("Compiled with Framework Version: {0}",
System.Reflection.Assembly.GetExecutingAssembly().ImageRuntimeVersion);
Console.WriteLine();
Console.WriteLine("Sort Test:\tNo extra string added");
ArrayTest(IncludeExtraString.None, null);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' inserted at
beginning", extra);
ArrayTest(IncludeExtraString.FirstElement, extra);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' inserted at middle",
extra);
ArrayTest(IncludeExtraString.MiddleElement, extra);
Console.WriteLine();
Console.WriteLine("Sort Test:\tExtra string '{0}' added to end", extra);
ArrayTest(IncludeExtraString.LastElement, extra);
}
static void ArrayTest(IncludeExtraString includeString, string extraString)
{
DateTime start, end;
string[] strArray = CreateArray(includeString, extraString);
#if CLR_V2
System.Collections.Generic.List<string> genericList =
new System.Collections.Generic.List<string>(strArray.Length);
genericList.AddRange(strArray);
start = DateTime.Now;
genericList.Sort();
end = DateTime.Now;
Console.WriteLine("List<string>:\t{0}(s)", ((TimeSpan)(end -
start)).TotalSeconds);
#endif
ArrayList arrayList = new ArrayList(strArray.Length);
arrayList.AddRange(strArray);
start = DateTime.Now;
arrayList.Sort();
end = DateTime.Now;
Console.WriteLine("ArrayList:\t{0}(s)", ((TimeSpan)(end -
start)).TotalSeconds);
}
static string[] CreateArray(IncludeExtraString includeString, string
extraString)
{
ArrayList list = new ArrayList();
char[] charString = new char[3];
for (int firstChar = 0; firstChar < 26; firstChar++)
{
charString[0] = Convert.ToChar('a' + firstChar);
for (int secondChar = 0; secondChar < 26; secondChar++)
{
charString[1] = Convert.ToChar('a' + secondChar);
for (int thirdChar = 0; thirdChar < 26; thirdChar++)
{
charString[2] = Convert.ToChar('a' + thirdChar);
list.Add(new string(charString));
}
}
}
switch (includeString)
{
case IncludeExtraString.FirstElement:
list.Insert(0, extraString);
break;
case IncludeExtraString.MiddleElement:
list.Insert(list.Count / 2, extraString);
break;
case IncludeExtraString.LastElement:
list.Add(extraString);
break;
}
return (string[])list.ToArray(typeof(string));
}
}