I have an ArrayList that contains,
[0] = \"1\"
[1] = \"10\"
[2] = \"2\"
[3] = \"15\"
[4] = \"17\"
[5] = \"5\"
[6] = \"6\"
[7] = \"27\"
[8] = \"8\"
[9] = \"9\"
If you can get the ArrayList items into a strongly typed container such as List<String> or String[] then Linq makes it easy to do the rest. The following implementation parses the string values only once and creates an anonymous type for each with the original string and its integer value.
public void Test_SortArrayList()
{
ArrayList items = new ArrayList(new []{"1", "10", "2", "15", "17", "5", "6", "27", "8", "9"});
string[] strings = (string[])items.ToArray(typeof(string));
List<string> result = strings
.Select(x => new
{
Original = x,
Value = Int32.Parse(x)
})
.OrderBy(x => x.Value)
.Select(x => x.Original)
.ToList();
result.ForEach(Console.WriteLine);
}
You'll be better of creating another array with Int
values and then sorting it with ArrayList.Sort()
. You could call ArrayList.Sort()
and pass it a delegate that will compare those strings as numbers but it will be slower. How much slower depends on size of your array and I personally think for sizes less then 100 it doesn't really matter.
There are numerous sort methods in the framework including ArrayList.Sort. The problem is that they are all going to sort alphabetically and not numerically. You'll need to write a custom sorter that understands numeric sorts.
Try the following (some argument checking left out for brevity)
public class NumericComparer : IComparer {
public int Compare(object x, object y) {
string left = (string)x;
string right = (string)y;
int max = Math.Min(left.Length, right.Length);
for ( int i = 0; i < max; i++ ) {
if ( left[i] != right[i] ) {
return left[i] - right[i];
}
}
return left.Length - right.Length;
}
}
list.Sort(new NumericComparer());
This is the safest way
aryList is your ArrayList instance
object[] list = aryList.ToArray();
Array.Sort<object>
(
list,
delegate(object x, object y)
{
int a = 0, b = 0;
if (x == y) return 0;
if (x == null || y == null)
return x == null ? -1 : 1;
int.TryParse(x.ToString(), out a);
int.TryParse(y.ToString(), out b);
return a.CompareTo(b);
}
);
result saved into "list" object array
Implement custom comparer and pass it to ArrayList.Sort()
Complete Code:
using System;
using System.Collections;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
ArrayList a = new ArrayList();
a.Add("1");
a.Add("13");
a.Add("3");
a.Add("25");
a.Add("2");
a.Add("12");
a.Sort(new CustomComparer());
foreach (String s in a)
Console.WriteLine(s);
Console.Read();
}
}
public class CustomComparer : IComparer
{
Comparer _comparer = new Comparer(System.Globalization.CultureInfo.CurrentCulture);
public int Compare(object x, object y)
{
// Convert string comparisons to int
return _comparer.Compare(Convert.ToInt32(x), Convert.ToInt32(y));
}
}
}
Output:
1 2 3 12 13 25
If the values are all ints then why not store them as ints? That would make sorting easier and faster.
In what other ways are the values used? If they're only used as strings and only sorted once then it's probably sensible to leave them as they are - as strings.
On the other hand, if they're used in maths ops then it's best to store them as ints.