2

我有以下未排序的列表:

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, (avg) Zeta, Beta, (avg) Beta, Alpha, (avg) Alpha

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

4

8 回答 8

6

这应该可以满足您的需要,假设“(avg)”是唯一的特殊前缀

这将对不包括“(avg)”的所有字符串进行降序排序,然后它将按字符串长度排序,这样带有“(avg)”前缀的字符串将排在没有前缀的字符串之后

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

最后结果:

  • 泽塔
  • (平均)泽塔
  • 贝塔
  • (平均)测试版
  • Α
  • (平均)阿尔法
于 2012-12-28T02:29:14.583 回答
3

以下是使用 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);

邮编/聚合

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;
于 2012-12-28T03:19:29.560 回答
1

将列表拆分为两个列表,一个正常,一个平均。对它们进行排序。

然后,进行手动“拉链合并”。

于 2012-12-28T02:49:25.433 回答
1

您可能应该创建自己的自定义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.
    }
}

检查xy是否与您的模式匹配。如果两者都不做,则使用标准比较操作。基本上,如果一个(并且只有一个)与模式匹配,您只需要自定义比较操作。

如果x与模式匹配而y不匹配,则剥离x并使用操作检查x的剥离版本与yString.Compare(...)是否匹配。如果y与模式匹配而x不匹配,则剥离y并使用操作检查y的剥离版本与xString.Compare(...)对比。

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

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


最后一点......如有必要,请随时优化。这是我心血来潮的未经测试的代码。逻辑在那里,我希望。但是,可能出现了拼写错误。

希望有帮助。

于 2012-12-28T02:52:24.140 回答
0

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

var result = myUnsortedList.OrderBy(x => x, new MyComparer());
于 2012-12-28T02:29:32.820 回答
0

我觉得您为此使用了错误的数据结构。为什么不使用 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];
}
于 2012-12-28T02:42:24.860 回答
0

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

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
于 2012-12-28T02:56:39.807 回答
0

在一行中:

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]));
    }
}
于 2012-12-28T03:32:34.220 回答