C# 使用自己的IComparer<;T>;与Linq OrderBy合作
我有一个通用的C# 使用自己的IComparer<;T>;与Linq OrderBy合作,c#,linq,sql-order-by,icomparer,C#,Linq,Sql Order By,Icomparer,我有一个通用的 List<MyClass> 它支持使用linq进行排序: protected override void ApplySortCore( PropertyDescriptor property, ListSortDirection direction) { _sortProperty = property; _sortDirection = direction; var items = this.Items;
List<MyClass>
它支持使用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;
}
但是,默认比较器按如下方式排序:
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]);
}
}
}
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;
}
}
200906/1200906/10
200906/11
200906/12
200906/2
在这种情况下,这是令人讨厌的 现在我想用我自己的
IComparer
与此进行比较。看起来是这样的:
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]);
}
}
}
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;
}
}
当我调试代码时,我看到MyComparer.Compare(object,object)
被多次调用,并为Compare方法返回正确的值(-1,0,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的右键更改项的值根本不会更改绑定列表。您应该添加:
this.Items = items;
在方法的底部。排序列表仅绑定到局部变量项,而不绑定到绑定列表的items属性,因此它保持未排序状态
[编辑]基本上,您只是在丢弃排序工作的结果;-) 我遇到了一般自然排序的问题,并将解决方案写在了这里:
公共类NaturalSortComparer:IComparer,IDisposable
{
私人住宅;
公共自然排序比较器(bool inAscendingOrder=true)
{
this.isAscending=inAscendingOrder;
}
#地区I比较成员
公共整数比较(字符串x、字符串y)
{
抛出新的NotImplementedException();
}
#端区
#地区I比较成员
int IComparer.Compare(字符串x、字符串y)
{
如果(x==y)
返回0;
字符串[]x1,y1;
如果(!table.TryGetValue(x,out x1))
{
x1=Regex.Split(x.Replace(“,”),“([0-9]+)”);
表.增加(x,x1);
}
如果(!table.TryGetValue(y,out y1))
{
y1=正则表达式拆分(y.Replace(“,”),“([0-9]+)”);
表.添加(y,y1);
}
int returnVal;
对于(int i=0;ix1.长度)
{
returnVal=1;
}
否则,如果(x1.长度>y1.长度)
{
returnVal=-1;
}
其他的
{
returnVal=0;
}
return isascing?returnVal:-returnVal;
}
私有静态int-PartCompare(字符串左、字符串右)
{
int x,y;
如果(!int.TryParse(左,外x))
返回左侧。比较(右侧);
如果(!int.TryParse(右,out y))
返回左侧。比较(右侧);
返回x.CompareTo(y);
}
#端区
私有字典表=新字典();
公共空间处置()
{
表1.Clear();
table=null;
}
}
您可以使用Alphanum算法:
(...)
items.OrderBy(x => property.GetValue(x), new AlphanumComparator())
(...)
/*
*Alphanum算法是一种改进的字符串排序算法
*包含数字。而不是像这样按ASCII顺序对数字进行排序
*作为一种标准排序,该算法按数字顺序对数字进行排序。
*
*Alphanum算法在http://www.DaveKoelle.com
*
*基于Dave Koelle的Alphanum算法的Java实现。
*乔纳森·拉克伍德撰稿
*
*由Dominik Hurnaus改编为
*-正确排序一个单词以另一个单词开头的单词
*-性能稍好
*
*根据麻省理工学院许可证发布-https://opensource.org/licenses/MIT
*
*特此免费向获得许可的任何人授予许可
*本软件及相关文档文件(“软件”)的副本,
*不受限制地处理软件,包括但不限于
*使用、复制、修改、合并、发布、分发、再许可、,
*和/或出售软件副本,并允许
*为此提供的软件应符合以下条件:
*
*应包括上述版权声明和本许可声明
*在软件的所有副本或主要部分。
*
*软件按“原样”提供,无任何形式的担保,
*明示或暗示,包括但不限于
*适销性、特定用途适用性和非侵权性。
*在任何情况下,作者或版权持有人均不对任何索赔负责,
*损害赔偿或其他责任,无论是在合同诉讼、侵权诉讼或
*否则,由本软件或
*在软件中使用或进行其他交易。
*
*/
使用制度;
使用系统集合;
使用系统文本;
/*
*请与上的最新Java版本进行比较http://www.DaveKoelle.com
*查看最新的修改
*/
名称空间字母计算器
{
公共类字母计算器:IComparer
{
私有枚举ChunkType{字母数字,数字};
私有布尔InChunk(char ch,char otherCh)
{
ChunkType类型=ChunkType.字母数字;
如果(字符为数字(其他字符))
{
type=ChunkType.Numeric;
}
if((type==ChunkType.Alphanumeric&&char.IsDigit(ch))
||(type==ChunkType.Numeric&&!char.IsDigit(ch)))
{
返回false;
}
返回true;
}
公共整数比较(对象x、对象y)
{
字符串s1=x作为字符串;
字符串s2=y
/*
* The Alphanum Algorithm is an improved sorting algorithm for strings
* containing numbers. Instead of sorting numbers in ASCII order like
* a standard sort, this algorithm sorts numbers in numeric order.
*
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
*
* Based on the Java implementation of Dave Koelle's Alphanum algorithm.
* Contributed by Jonathan Ruckwood <jonathan.ruckwood@gmail.com>
*
* Adapted by Dominik Hurnaus <dominik.hurnaus@gmail.com> to
* - correctly sort words where one word starts with another word
* - have slightly better performance
*
* Released under the MIT License - https://opensource.org/licenses/MIT
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
using System;
using System.Collections;
using System.Text;
/*
* Please compare against the latest Java version at http://www.DaveKoelle.com
* to see the most recent modifications
*/
namespace AlphanumComparator
{
public class AlphanumComparator : IComparer
{
private enum ChunkType {Alphanumeric, Numeric};
private bool InChunk(char ch, char otherCh)
{
ChunkType type = ChunkType.Alphanumeric;
if (char.IsDigit(otherCh))
{
type = ChunkType.Numeric;
}
if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
|| (type == ChunkType.Numeric && !char.IsDigit(ch)))
{
return false;
}
return true;
}
public int Compare(object x, object y)
{
String s1 = x as string;
String s2 = y as string;
if (s1 == null || s2 == null)
{
return 0;
}
int thisMarker = 0, thisNumericChunk = 0;
int thatMarker = 0, thatNumericChunk = 0;
while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
{
if (thisMarker >= s1.Length)
{
return -1;
}
else if (thatMarker >= s2.Length)
{
return 1;
}
char thisCh = s1[thisMarker];
char thatCh = s2[thatMarker];
StringBuilder thisChunk = new StringBuilder();
StringBuilder thatChunk = new StringBuilder();
while ((thisMarker < s1.Length) && (thisChunk.Length==0 ||InChunk(thisCh, thisChunk[0])))
{
thisChunk.Append(thisCh);
thisMarker++;
if (thisMarker < s1.Length)
{
thisCh = s1[thisMarker];
}
}
while ((thatMarker < s2.Length) && (thatChunk.Length==0 ||InChunk(thatCh, thatChunk[0])))
{
thatChunk.Append(thatCh);
thatMarker++;
if (thatMarker < s2.Length)
{
thatCh = s2[thatMarker];
}
}
int result = 0;
// If both chunks contain numeric characters, sort them numerically
if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
{
thisNumericChunk = Convert.ToInt32(thisChunk.ToString());
thatNumericChunk = Convert.ToInt32(thatChunk.ToString());
if (thisNumericChunk < thatNumericChunk)
{
result = -1;
}
if (thisNumericChunk > thatNumericChunk)
{
result = 1;
}
}
else
{
result = thisChunk.ToString().CompareTo(thatChunk.ToString());
}
if (result != 0)
{
return result;
}
}
return 0;
}
}
}
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);