Используйте собственный IComparer <T> с Linq OrderBy
У меня есть общий
List<MyClass>
где MyClass
имеет свойство InvoiceNumber
, которое содержит такие значения, как:
200906/1
200906/2
..
200906/10
200906/11
200906/12
Мой список привязан к
BindingList<T>
который поддерживает сортировку с помощью linq:
protected override void ApplySortCore(
PropertyDescriptor property, ListSortDirection direction)
{
_sortProperty = property;
_sortDirection = direction;
var items = this.Items;
switch (direction)
{
case ListSortDirection.Ascending:
items = items.OrderByDescending(x => property.GetValue(x)).ToList();
break;
case ListSortDirection.Descending:
items = items.OrderByDescending(x => property.GetValue(x)).ToList();
break;
}
this.Items = items;
}
Однако сопоставление по умолчанию сортирует (как предполагается) следующим образом:
200906/1
200906/10
200906/11
200906/12
200906/2
что в этом случае неприятно.
Теперь я хочу использовать свой IComparer<T>
с этим. Это выглядит так:
public class MyComparer : IComparer<Object>
{
public int Compare(Object stringA, Object stringB)
{
String[] valueA = stringA.ToString().Split('/');
String[] valueB = stringB.ToString().Split('/');
if(valueA .Length != 2 || valueB .Length != 2)
return String.Compare(stringA.ToString(), stringB.ToString());
if (valueA[0] == valueB[0])
{
return String.Compare(valueA[1], valueB[1]);
}
else
{
return String.Compare(valueA[0], valueB[0]);
}
}
}
и изменил код ApplySortCore
, чтобы использовать этот IComparer
:
case ListSortDirection.Ascending:
MyComparer comparer = new MyComparer();
items = items.OrderByDescending(
x => property.GetValue(x), comparer).ToList();
break;
Когда я отлаживаю свой код, я вижу, что MyComparer.Compare(object, object)
вызывается несколько раз и возвращает правильные значения (-1, 0, 1) для метода сравнения.
Но мой список по-прежнему сортируется как "неправильный" способ. Я что-то упускаю? Я понятия не имею.
Ответы
Ответ 1
Ваш компартер выглядит неправильно. Вы по-прежнему просто сортируете текстовое упорядочение по умолчанию. Конечно, вы хотите разбора двух чисел и сортировки на основе этого:
public int Compare(Object stringA, Object stringB)
{
string[] valueA = stringA.ToString().Split('/');
string[] valueB = stringB.ToString().Split('/');
if (valueA.Length != 2 || valueB.Length != 2)
{
stringA.ToString().CompareTo(stringB.ToString()));
}
// Note: do error checking and consider i18n issues too :)
if (valueA[0] == valueB[0])
{
return int.Parse(valueA[1]).CompareTo(int.Parse(valueB[1]));
}
else
{
return int.Parse(valueA[0]).CompareTo(int.Parse(valueB[0]));
}
}
(Обратите внимание, что это не соответствует вашему вопросу о том, что вы отлаживали и проверяли, что Compare возвращает правильное значение, но я боюсь, что я подозреваю человеческую ошибку на этом фронте.)
Кроме того, Sven right - изменение значения items
не изменяет ваш список привязок вообще. Вы должны добавить:
this.Items = items;
внизу вашего метода.
Ответ 2
Я столкнулся с проблемой общей естественной сортировки и разместил здесь решение:
Естественная сортировка с Linq OrderBy()
Ответ 3
Вы можете использовать Алфавитный алгоритм:
(...)
items.OrderBy(x => property.GetValue(x), new AlphanumComparator())
(...)
где
AlphanumComparator http://www.davekoelle.com/files/AlphanumComparator.cs
Ответ 4
Не можем ли мы сделать так:
public class MyComparer : IComparer<string>
{
public int Compare(string stringA, string stringB)
{
string small = stringA;
string big = stringB;
if (stringA.Length > stringB.Length)
{
small = stringB;
big = stringA;
}
else if (stringA.Length < stringB.Length)
{
small = stringA;
big = stringB;
}
for (int j = 0; j < small.Length; j++)
{
if (Convert.ToInt32(small[j]) > Convert.ToInt32(big[j])) return -1;
if (Convert.ToInt32(small[j]) < Convert.ToInt32(big[j])) return 1;
}
//big is indeed bigger
if (big.Length > small.Length) return 1;
//finally they are smae
return 0;
}
}
Использование:
string[] inputStrings = {"_abc*&","#almnp","abc" };
//string[] inputStrings = { "#", "_", "_a", "@", "_" };
MyComparer computer = new MyComparer();
var kola = inputStrings.OrderBy(x => x, new MyComparer()).ToArray();
Это то же самое, что:
Array.Sort(inputStrings, StringComparer.Ordinal);
Ответ 5
Сортированный список привязан только к элементам локальной переменной, а не к свойству Items вашего списка привязки, поэтому он остается несортированным.
[Изменить] В принципе, вы просто отбрасываете результат ваших усилий по сортировке; -)