排序算法- c#
本文关键字:算法 排序 | 更新日期: 2023-09-27 17:49:39
我有以下未排序的列表:
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
来完成排序
假设"(avg)"是唯一的特殊前缀
这将对所有字符串进行降序排序,不包括"(avg)"然后它将按字符串长度排序,这样带有"(avg)"前缀的字符串将排在没有
的字符串之后。var result = myUnsortedList.OrderByDescending(x => x.Replace("(avg) ", "")).ThenBy(x => x.Length);
最终结果:
- ζ
- (avg)ζ β
- (avg)β α
- (avg)α
这里有几种方法可以用LINQ实现这一点,同时如果它们以不同于您所呈现的顺序出现,也可以正确地对值进行排序。例如,如果"(avg) Zeta"出现在"Zeta"之前,则在排序后,后者仍应优先出现。
下面是示例列表,重新排序以匹配我上面描述的内容:
var myUnsortedList = new List<string>
{
"Alpha",
"(avg) Alpha",
"(avg) Zeta",
"Zeta",
"Beta",
"(avg) Beta"
};
λ语法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;
将列表分成两个列表,一个是正常列表,一个是平均列表。把它们都排序。
然后,执行手动"拉链合并"。
您应该创建自己的自定义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.
}
}
检查x和y是否匹配您的模式。如果两者都不匹配,则使用标准比较操作。基本上,只有当有一个(且只有一个)匹配模式时,您才需要自定义比较操作。
如果x匹配模式,而y不匹配,则剥离x并使用String.Compare(...)
操作检查x的剥离版本与y的对比。如果y匹配模式,而x不匹配,则剥离y,并使用String.Compare(...)
操作对照x检查剥离后的y版本。
我更新了我的答案,以展示如何通过为大小写/区域性选项公开自定义比较器的静态只读实例来复制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排序中使用自己的逻辑,您应该实现自己的比较器,并使用它的实例作为OrderBy
或OrderByDescending
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]));
}
}