Reputation: 3314
I have a list of string containing "Others"
. I am getting this list for drop down. I am sorting this list alphabetically. But I need "Others"
always at end of list. I don't want to add this element after sorting which is one solution. Is there any other way to do the same like by using custom comparer of .Sort()
method. I tried like below but no solution.
public class EOComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null)
{
if (y == null)
{
// If x is null and y is null, they're
// equal.
return 0;
}
else
{
// If x is null and y is not null, y
// is greater.
return -1;
}
}
else
{
// If x is not null...
//
if (y == null)
// ...and y is null, x is greater.
{
return 1;
}
else
{
if (x.ToLower().Contains("other"))
{
return -1;
}
else
{
// If the strings are of equal length,
// sort them with ordinary string comparison.
//
return x.CompareTo(y);
}
}
}
}
and calling it as :
EOComparer c = new EOComparer();
a.Sort((x, y) => c.Compare(x.OptionValue, y.OptionValue));
return a;
Please help if it is possible.
Upvotes: 15
Views: 10600
Reputation: 1
Suppose we have objects with the following list items.
object.Text = "a" object.Value = 1
object.Text = "b" object.Value = 2
object.Text = "other" object.Value = 3
object.Text = "c" object.Value = 4
the following works for me:
var oList = objects.OrderBy(i => i.Text != "other").ThenBy(i => i.Text);
Upvotes: 0
Reputation: 54801
This is a fine answer, but I thought I would fix your comparer:
Test:
[TestCase(new string[0], new string[0])]
[TestCase(new[] { "a" }, new[] { "a" })]
[TestCase(new[] { "a", "b" }, new[] { "a", "b" })]
[TestCase(new[] { "b", "a" }, new[] { "a", "b" })]
[TestCase(new[] {"others"}, new[] {"others"})]
[TestCase(new[] {"a", "others"}, new[] {"a", "others"})]
[TestCase(new[] {"others", "a"}, new[] {"a", "others"})]
[TestCase(new[] {"others", "x"}, new[] {"x", "others"})]
[TestCase(new[] {"Others", "x"}, new[] {"x", "Others"})]
[TestCase(new[] { "othersz", "others" }, new[] { "othersz", "others" })]
[TestCase(new[] {"z", "y", "x", "others", "b", "a", "c"},
new[] {"a", "b", "c", "x", "y", "z", "others"})]
public void CanSortWithOthersAtEnd(string[] input, string[] expectedSorted)
{
var a = new List<string>(input);
var c = new EOComparer();
a.Sort(c.Compare);
CollectionAssert.AreEqual(expectedSorted, a);
}
Comparer:
public sealed class EOComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (IsOthers(x)) return 1;
if (IsOthers(y)) return -1;
return string.Compare(x, y, StringComparison.Ordinal);
}
private static bool IsOthers(string str)
{
return string.Compare(str, "others", StringComparison.OrdinalIgnoreCase) == 0;
}
}
Note how my use of string.Compare
avoids all == null
checks. And how StringComparison.OrdinalIgnoreCase
avoids .ToLower()
and thus avoids creating copies of the strings.
Upvotes: 12
Reputation: 7903
Use this logic
List<string> l = new List<string>{ "z", "y", "x", "other", "b", "a", "c" };
var result = l.OrderBy(i => i == "other").ThenBy(i => i).ToList();
result.ForEach(Console.WriteLine);
Output:
a b c x y z other
If you want other
to be on top of the list make it
var result = l.OrderBy(i => i != "other").ThenBy(i => i).ToList();
Output:
other a b c x y z
Upvotes: 31