繁体   English   中英

排序算法 - C#

[英]Sorting Algorithm - C#

我有以下未排序的列表:

List<string> myUnsortedList = New List<string>();

myUnsortedList.Add("Alpha");
myUnsortedList.Add("(avg) Alpha");
myUnsortedList.Add("Zeta");
myUnsortedList.Add("Beta");
myUnsortedList.Add("(avg) Beta");
myUnsortedList.Add("(avg) Zeta");

我想按字母顺序降序排序,然后在正常值之后使用(avg)值:

最终结果:Zeta,(平均)Zeta,Beta,(平均)Beta,Alpha,(平均)Alpha

我的应用程序是用C#编写的,我想使用LINQ来完成排序

这应该适用于你需要的东西,假设“(avg)”是唯一的特殊前缀

这将命令所有下降的顺序不包括“(平均)”然后它将按字符串长度排序这样具有“(avg)”前缀的字符串将在没有

var result = myUnsortedList.OrderByDescending(x => x.Replace("(avg) ", "")).ThenBy(x => x.Length);

最后结果:

  • 泽塔
  • (平均)泽塔
  • Beta版
  • (平均)Beta
  • Α
  • (平均)阿尔法

这里有几种方法可以使用LINQ来解决这个问题,同时如果值按照您提供的顺序排列,也可以正确排序。 例如,如果“(avg)Zeta”出现在“Zeta”之前,则后者应该在排序后首先出现。

这是样本列表,重新排序以匹配我上面描述的内容:

var myUnsortedList = new List<string>
{
    "Alpha",
    "(avg) Alpha",
    "(avg) Zeta",
    "Zeta",
    "Beta",
    "(avg) Beta"
};

Lambda语法

string prefix = "(avg)";
var result = myUnsortedList.Select(s => new
                           {
                               Value = s,
                               Modified = s.Replace(prefix, "").TrimStart(),
                               HasPrefix = s.StartsWith(prefix)
                           })
                           .OrderByDescending(o => o.Modified)
                           .ThenBy(o => o.HasPrefix)
                           .Select(o => o.Value);

Zip / Aggregate

string prefix = "(avg)";
var avg = myUnsortedList.Where(o => o.StartsWith(prefix))
                        .OrderByDescending(o => o);
var regular = myUnsortedList.Where(o => !o.StartsWith(prefix))
                            .OrderByDescending(o => o);
var result = regular.Zip(avg, (f, s) => new { First = f, Second = s })
                    .Aggregate(new List<string>(), (list, o) =>
                                   new List<string>(list) { o.First, o.Second });

查询语法和字符串拆分

这个类似于lambda语法,除了我没有使用prefix来确定哪个字符串有前缀。 相反,我正在拆分空间,如果拆分结果有多个项目,那么我假设它有一个前缀。 接下来,我根据值和前缀的可用性进行排序。

var result = from s in myUnsortedList
             let split = s.Split(' ')
             let hasPrefix = split.Length > 1
             let value = hasPrefix ? split[1] : s
             orderby value descending, hasPrefix
             select s;

将列表拆分为两个列表,一个是普通列表,一个是平均值。 对它们进行排序。

然后,做一个手册“Zipper Merge”。

你应该创建自己的自定义IComparer<T>

class MyCustomComparer : IComparer<string>
{
    private readonly StringComparison StringComparer;

    public static readonly MyCustomComparer Ordinal =
        new MyCustomComparer(StringComparison.Ordinal);
    public static readonly MyCustomComparer OrdinalIgnoreCase =
        new MyCustomComparer(StringComparison.OrdinalIgnoreCase);
    // etc.

    private MyCustomComparer(StringComparison stringComparer)
    {
        StringComparer = stringComparer;
    }

    public int Compare(string x, string y)  
    {  
        bool isMatchedX = IsMatchedPattern(x);
        bool isMatchedY = IsMatchedPattern(y);

        if (isMatchedX&& !isMatchedY ) // x matches the pattern.
        {
            return String.Compare(Strip(x), y, StringComparer);
        }
        if (isMatchedY && !isMatchedX) // y matches the pattern.
        {
            return String.Compare(Strip(y), x, StringComparer);
        }

        return String.Compare(x, y, StringComparison.Ordinal);
    }

    private static bool isMatchedPattern(string str)
    {
        // Use some way to return if it matches your pattern.
        // StartsWith, Contains, Regex, etc.
    }

    private static string Strip(string str)
    {
        // Use some way to return the stripped string.
        // Substring, Replace, Regex, etc.
    }
}

and match your pattern. 检查与您的模式匹配。 如果两者都没有,则使用标准比较操作。 基本上,如果一个(并且只有一个)匹配模式,则只需要自定义比较操作。

matches the pattern and doesn't, then strip and check the stripped version of against using the String.Compare(...) operation. 如果模式匹配和不,然后剥去和使用所述检查的剥离版本针对 String.Compare(...)操作。 matches the pattern and doesn't, then strip and check the stripped version of against using the String.Compare(...) operation. 如果的模式匹配,并且没有,那么剥离和使用所述检查的剥离版本针对 String.Compare(...)操作。

我更新了我的答案,以展示如何通过为case / culture选项公开自定义比较器的静态只读实例来复制StringComparison工作方式。

最后,将LINQ与自定义比较器一起使用: myList.OrderBy(x => x, MyCustomComparer.Ordinal);


最后一点说明......如有必要,请随意优化。 这是我心中想到的未经测试的代码。 我希望,逻辑在那里。 但是,可能已经发生过拼写错误。

希望有所帮助。

另一种方法是实现一些比较器说MyComparer实现IComparer<string> ,然后:

var result = myUnsortedList.OrderBy(x => x, new MyComparer());

我觉得你正在使用错误的数据结构。 为什么不使用SortedDictionary并使其成为“name => avg”

未经测试的,可能正在运行的代码:

SortedDictionary<string, int> dict = new SortedDictionary<string, int>();
dict.Add("Alpha", 10);
dict.Add("Beta", 20);
dict.Add("Zeta", 30);

foreach(string key in dict.Keys.Reverse())
{
   int avg = dict[key];
}

在linq排序中使用您自己的逻辑您应该实现自己的Comparer并将其实例用作OrderByOrderByDescending linq方法中的第二个参数,如下所示:

namespace ConsoleApplication71
{
    public class AVGComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            // Null checkings are necessary to prevent null refernce exceptions
            if((x == null) && (y == null)) return 0;
            if(x == null) return -1;
            if(y == null) return 1;

            const string avg = @"(avg) ";

            if(x.StartsWith(avg) || y.StartsWith(avg))
            {
                return x.Replace(avg, string.Empty).CompareTo(y.Replace(avg, string.Empty));
            }

            return x.CompareTo(y);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<string> myUnsortedList = new List<string>();

            myUnsortedList.Add("Alpha");
            myUnsortedList.Add("(avg) Alpha");
            myUnsortedList.Add("Zeta");
            myUnsortedList.Add("Beta");
            myUnsortedList.Add("(avg) Beta");
            myUnsortedList.Add("(avg) Zeta");

            var mySortedList = myUnsortedList.OrderByDescending(s => s, new AVGComparer());

            foreach (string s in mySortedList)
            {
                Console.WriteLine(s);
            }
        }
    }
}

输出是:

Zeta
(avg) Zeta
Beta
(avg) Beta
Alpha
(avg) Alpha

在一行:

var sorted = myUnsortedList.OrderByDescending(x => x.Replace("(avg) ", "")).ThenBy(x=> x.Contains("(avg)")).ToList();

这是一个通过测试(nunit):

[Test]
public void CustomSort()
{
    var myUnsortedList = new List<string> { "Zeta", "Alpha", "(avg) Alpha", "Beta", "(avg) Beta", "(avg) Zeta" };
    var EXPECTED_RESULT = new List<string> { "Zeta", "(avg) Zeta", "Beta", "(avg) Beta", "Alpha", "(avg) Alpha" };

    var sorted = myUnsortedList.OrderByDescending(x => x.Replace("(avg) ", "")).ThenBy(x=> x.Contains("(avg)")).ToList();

    for (int i = 0; i < myUnsortedList.Count; i++)
    {
        Assert.That(sorted[i], Is.EqualTo(EXPECTED_RESULT[i]));
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM