自然排序问题

时间:2013-01-29 16:04:26

标签: c# sorting icomparer

我一直在尝试使用从here借来的代码来整理我的应用程序的自定义对象的集合。通常排序工作正常,直到我遇到以下字符串

D-016.0,
D-016.,
D-016.00,
D-016.000 001,
D-016.000 002,
D-016.000,
D-016.00 003,
D-016.00 002,
D-016. 001,
D-016. 002,
D-016.0 001,
D-016.00 001

由于一些非常奇怪的原因,按顺序返回集合

D-016.00,
D-016.000,
D-016.0,
D-016.000 001,
D-016. 001,
D-016.0 001,
D-016.00 001,
D-016.00 002,
D-016.000 002,
D-016. 002,
D-016.00 003,
D-016.

我希望看到的集合看起来像Windows资源管理器将显示哪个应该是

D-016. 001,
D-016. 002,
D-016.,
D-016.000 001,
D-016.000 002,
D-016.000,
D-016.00 001,
D-016.00 002,
D-016.00 003,
D-016.00,
D-016.0 001,
D-016.0,

根据Michael Kniskern发布的Natural Sort Order in C#的建议,我试图实现使用shlwapi.dll的答案,这将返回我希望按照上面列出的最后一个集合看到它的顺序。但是,此方法仅适用于Windows 7,并在Windows XP中返回不均匀的集合。

我怀疑列为D-016.00,D-016.0和D-016.000的文件在解析为int时会得到连接的0列表,这会导致此错误。但是我无法准确理解如何解决这个问题(对于这些比较器接口来说太新了)。任何人都可以为此建议一个解决方案吗?

以下是我目前正在使用的代码

public class NaturalSorter<T> : IComparer<string>, IDisposable
{
    private readonly bool ascending;
    private Dictionary<string, string[]> table = new Dictionary<string, string[]>();


    public NaturalSorter(bool inAscendingOrder = true)
    {
        ascending = inAscendingOrder;
    }

    #region IComparer Members


    public int Compare(string[] x, string[] y)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region IComparer Members

    int IComparer<string>.Compare(string x, string y)
    {
        if (x == y)
            return 0;

        string[] x1, y1;

        if (!table.TryGetValue(x, out x1))
        {
            x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)");
            table.Add(x, x1);
        }

        if (!table.TryGetValue(y, out y1))
        {
            y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)");
            table.Add(y, y1);
        }

        int returnVal = 0;

        for (int i = 0; i < x1.Length && i < y1.Length; i++)
        {
            if (x1[i] != y1[i])
            {
                returnVal = PartCompare(x1[i], y1[i]);
                return ascending ? returnVal : -returnVal;
            }
        }

        if (y1.Length > x1.Length)
        {
            returnVal = 1;
        }
        else if (x1.Length > y1.Length)
        {
            returnVal = -1;
        }
        else
        {
            returnVal = 0;
        }

        return ascending ? returnVal : -returnVal;
    }

    private static int PartCompare(string left, string right)
    {
        int x, y;
        if (!int.TryParse(left, out x))
            return left.CompareTo(right);

        if (!int.TryParse(right, out y))
            return left.CompareTo(right);

        return x.CompareTo(y);
    }

    #endregion

    public void Dispose()
    {
        table.Clear();
        table = null;
    }
}

1 个答案:

答案 0 :(得分:0)

这是我能想到的最好的:

用以下内容替换拆分:

if (!table.TryGetValue(x, out x1))
{
    x1 = Regex.Split(x, @"([0-9]+|\.)");
    table.Add(x, x1);
}

if (!table.TryGetValue(y, out y1))
{
    y1 = Regex.Split(y, @"([0-9]+|\.)");
    table.Add(y, y1);
}

并将以下内容添加到PartCompare()

的顶部
private static int PartCompare(string left, string right)
{
     if (left.Length > right.Length) return -1;
     else if (left.Length < right.Length) return 1;

     int x, y;
     ...

这会产生:

D-016. 001,
D-016. 002,
D-016.000 001,
D-016.000 002,
D-016.000,
D-016.00 001,
D-016.00 002,
D-016.00 003,
D-016.00,
D-016.0 001,
D-016.0,
D-016.,  // The one out-of-order item.