我有一个对象数组,所有对象都包含字符串属性。我想按字符串属性按字母顺序对对象进行排序,以使具有空字符串属性的对象位于列表的末尾。目前我有这个:
switches = switches.OrderBy(n => n.GetCurrentUser()).ToArray();
问题在于它将空字符串放在列表的顶部。如何将带有值(按字母顺序排列)的字符串的对象放在顶部,而将空字符串的对象放在底部的对象?
答案 0 :(得分:2)
您可以使用:
switches = switches
.Select(n => new { TheObject = n, User = n.GetCurrentUser() })
.OrderBy(x => String.IsNullOrEmpty(x.User) ? 1 : 0)
.ThenBy(x => x.User)
.Select(x => x.TheObject)
.ToArray();
这将首先建立两个组,一个组具有空用户,另一个组。 OrderBy
会将它们移到末尾,因为1大于0。如果希望它们位于顶部,请使用OrderByDescending
。
然后我使用ThenBy
按字母顺序排序,这仅对非空用户有效。
答案 1 :(得分:1)
OrderBy具有accepts an IComparer<>T的重载。这使您可以定义自己的排序规则。您可以从通用Comparer类开始,并覆盖Compare
方法,例如:
public class EmptyLastComparer: Comparer<string>
{
public override int Compare(string x, string y)
{
if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
{
return 1;
}
else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return 0;
}
else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return -1;
}
else
{
return x.CompareTo(y);
}
}
}
要使用它,请创建一个新的EmptyLastComparer()实例并将其传递给OrderBy
:
var myStrings = new[] { "c", "A","a", "A","b", " "," ",null };
var ordered=myStrings.OrderBy(x => x, new EmptyLastComparer());
字符串比较比仅比较两个字符串更为复杂。 String.Compare有重载,允许使用不区分大小写的比较,使用特定区域性等。自定义比较器可以在其构造函数中接受StringComparison
参数,以允许类似内容,例如:
public class EmptyLastComparer : Comparer<string>
{
private readonly StringComparison _comparison;
public EmptyLastComparer(StringComparison comparison=StringComparison.CurrentCulture)
{
_comparison = comparison;
}
public override int Compare(string x, string y)
{
if (String.IsNullOrWhiteSpace(x) && !String.IsNullOrWhiteSpace(y))
{
return 1;
}
else if (String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return 0;
}
else if (!String.IsNullOrWhiteSpace(x) && String.IsNullOrWhiteSpace(y))
{
return -1;
}
else
{
return String.Compare(x,y, _comparison);
}
}
}
也许甚至像StringComparer一样添加一些预定义的比较器:
public static EmptyLastComparer CurrentCulture =>
new EmptyLastComparer();
public static EmptyLastComparer CurrentCultureIgnoreCase =>
new EmptyLastComparer(StringComparison.CurrentCultureIgnoreCase);
public static EmptyLastComparer InvariantCulture =>
new EmptyLastComparer(StringComparison.InvariantCulture);
public static EmptyLastComparer InvariantCultureIgnoreCase =>
new EmptyLastComparer(StringComparison.InvariantCultureIgnoreCase);
public static EmptyLastComparer Ordinal =>
new EmptyLastComparer(StringComparison.Ordinal);
public static EmptyLastComparer OrdinalIgnoreCase =>
new EmptyLastComparer(StringComparison.OrdinalIgnoreCase);
并以相同的方式使用它们,而不必每次都分配一个新的比较器:
var ordered=myStrings.OrderBy(x => x, EmptyLastComparer.InvariantCultureIgnoreCase);
答案 2 :(得分:1)
您还可以使用内联比较器创建:
switches.OrderBy(n => n.GetCurrentUser(),
Comparer<string>.Create((a, b) =>
string.IsNullOrEmpty(a) && !string.IsNullOrEmpty(b)? 1
: !string.IsNullOrEmpty(a) && string.IsNullOrEmpty(b) ? -1
: string.Compare(a, b)));