如何在C#中对数组列表的元素进行排序

11

我有一个包含以下内容的ArrayList:

[0] = "1"
[1] = "10"
[2] = "2"
[3] = "15"
[4] = "17"
[5] = "5"
[6] = "6"
[7] = "27"
[8] = "8"
[9] = "9"

现在我需要对数组列表进行排序,使其变成:

[0] = "1"
[1] = "2"
[2] = "5"
[3] = "6"
[4] = "8"
[5] = "9"
[6] = "10"
[7] = "15"
[8] = "17"
[9] = "27"

最后我将从ArrayList中获取值并将它们用作'int' 值。我该怎么做?还是我应该先转换为int然后再排序?


你使用的是哪个版本的C#?使用的是哪个版本的Visual Studio?如果你没有使用.NET 1.1,那么你就不应该使用ArrayList。相反,你应该使用List<T>。在你的情况下,看起来像是List<string>。 - John Saunders
10个回答

16

如果你可以确保列表仅包含可以转换为整数的字符串,则使用 IEnumerable<T>.OrderBy 扩展方法,试试这个:

var sortedList = list.OrderBy(item => int.Parse(item));

如果你在使用 ArrayList 而不是 List<string>(不推荐这样做!),你需要先进行强制转换:

如果您使用的是 ArrayList,而不是 List<string>(不好!),则需要先进行强制转换:

var sortedList = list.Cast<string>().OrderBy(item => int.Parse(item));

正如JaredPar所指出的,您也可以定义自己的比较器,但在我看来,这需要做很多工作,而这个功能已经实现了。然而,它更有效率。


这样是行不通的。OP正在使用一个ArrayList。你需要在那里至少加一个.Cast<string>。 - JaredPar
似乎需要使用Linq。 - newenglander

6

框架中有许多排序方法,包括ArrayList.Sort。问题在于它们都会按字母顺序排序而不是数字顺序。您需要编写一个自定义排序器,能够理解数字排序。

尝试以下方法(为简洁起见省略了一些参数检查)

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());

2
为什么还要像字符串一样进行比较?它们都是数字吗?直接将它们解析为整数并返回结果不是更容易吗? - gbianchi
1
他会说那样做效率更低。 - Sean Bright
1
@gbianchi,@Sean是正确的。我进行字符比较的原因是这样做比解析成数字并进行比较要高效得多。将其解析为数字非常有效,但与进行字符比较相比,它有明显的性能差异。 - JaredPar
是的,逐个比较字符串的字符更有效率。不过可读性会稍差一些! ;) - John Feminella
除了性能之外,我的个人经验告诉我,在需要按自然顺序排序的“数字字符串”方面,当您得到“整数”作为字符串时,它们并不总是遵循Int32.MaxValue(并且对于文件名,我不得不处理它们超过Int64.MaxValue的情况!) - David
显示剩余3条评论

6

实现自定义比较器并将其传递给ArrayList.Sort()

完整代码:

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));
        }
    }
}

输出:

1 2 3 12 13 25


我认为对于用户想要的功能来说,这有点复杂了,但是我认为它能够解决问题。 - Jean Azzopardi
1
肯定可以解决问题。一旦创建了CustomComparer,用户只需将其作为参数添加到需要按数字顺序排序字符串文字的任何位置即可。 - Rashmi Pandit

4

或许你可以将值存储在一个强类型列表中,例如 List ,然后在使用时(如有必要)将其转换为字符串。像这样:

        List<int> intList = new List<int>(new int[] {3, 2, 1});

        intList.Sort();

        foreach (int theInt in intList)
        {
            System.Diagnostics.Debug.WriteLine(theInt.ToString());
        }

顺便提一下,不要将其声明为IList<int>,否则你会被List具有Sort()而IList没有的问题所困扰。 - Powerlord

1
你最好创建另一个包含Int值的数组,然后使用ArrayList.Sort()对其进行排序。你可以调用ArrayList.Sort()并传递一个委托来将这些字符串作为数字进行比较,但速度会慢一些。速度慢多少取决于数组的大小,我个人认为对于小于100的大小,速度并不重要。

0
 List<int> liDllCnt = new List<int>();
 for (int temp = 0; temp < alFileName.Count; temp++)
     liDllCnt.Add(Int32.Parse(alFileName[temp].ToString()));
 liDllCnt.Sort();

alFileName 是我使用的数组列表的名称。


如果这是你的解决方案,那么你需要将数据存储为整型。 - gbianchi

0

这是最安全的方法

aryList 是你的 ArrayList 实例

                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);
                        }
                    );

结果保存到“list”对象数组中


0
如果您可以将ArrayList项目放入强类型容器(例如List 或String []),那么Linq很容易完成其余工作。以下实现仅解析字符串值一次,并为每个字符串创建一个匿名类型及其整数值。
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);
}

0
如果这些值都是整数,为什么不将它们存储为整数呢?这样可以使排序更加容易和快速。
这些值还有其他用途吗?如果它们只被用作字符串,并且只排序一次,那么将它们保留为字符串可能是明智的选择。
另一方面,如果它们在数学运算中使用,则最好将它们存储为整数。

0

Arraylist 按大小写区分排序,升序。对某些人有帮助。

class ArrayCaseSensitive:IComparer
    {
        int IComparer.Compare(object x, object y)
        {
            return (new CaseInsensitiveComparer().Compare(x,y));
        }

    public static void Main(string[] args)
    {
            IComparer sc = new ArrayCaseSensitive();
           
        ArrayList arr = new ArrayList();
        arr.Add("AB");
        arr.Add("bc");
        arr.Add("1");
        arr.Sort(sc);
        foreach(var strs in arr)
        {
            Console.WriteLine(strs);
        }
        
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接