簡體   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