C# 使用 IComparer 对 x 列进行排序
C# Using IComparer to sort x number of columns
我希望能够按 x 列对数据进行排序,其中 x 不是常数。
上下文:我有一个 DataGridView(未绑定),其中有许多行。因为我想按不止一列排序,所以我创建了一个 class 实现 IComparer 以对网格行进行排序。我已经完成了对单个列进行排序的工作,但是我不确定现在如何更改此 class 以允许对大于 1.
的多个列进行排序
我之前看到的很多答案都提供了对两列或三列进行排序的示例,但是这些似乎是比较 A->B,然后是 B->C 等等。我正在寻找稍微更有活力的东西。
示例:
- 用户点击第4列;数据按记录的顺序排序
第 4 列;
- 用户然后点击第 6 列;数据按以下顺序排序
第 4 列中的记录然后第 6 列;
- 用户点击第2列;数据是
按第 4 列 THEN 第 6 列 THEN 第 2 列中的记录顺序排序;
等等
我目前的情况如下:
public class FormGrid : DataGridView
{
List<GridSortData> ColIndexSorts = new List<GridSortData>();
private class GridSortData
{
public int ColumnSortIndex;
public System.Windows.Forms.SortOrder SortOrder;
}
private class GridSort : System.Collections.IComparer
{
private static int SortOrder = 1;
private int SortingColumn;
public GridSort(System.Windows.Forms.SortOrder sortOrder, int ColumnToSort)
{
SortingColumn = ColumnToSort;
SortOrder = sortOrder == System.Windows.Forms.SortOrder.Ascending ? 1 : -1;
}
public int Compare(object x, object y)
{
FormGridRow FirstComparable = (FormGridRow)x;
FormGridRow SecondComparable = (FormGridRow)y;
int result = 1;
result = FirstComparable.Cells[SortingColumn].Value.ToString().CompareTo(SecondComparable.Cells[SortingColumn].Value.ToString());
return result * SortOrder;
}
}
private void TSortGrid(int ColIndexToSort, MouseButtons MouseButton)
{
GridSortData ColumnToSort = new GridSortData();
ColumnToSort.ColumnSortIndex = ColIndexToSort;
if (MouseButton == System.Windows.Forms.MouseButtons.Left)
{
ColumnToSort.SortOrder = System.Windows.Forms.SortOrder.Ascending;
}
else
{
ColumnToSort.SortOrder = System.Windows.Forms.SortOrder.Descending;
}
ColIndexSorts.Add(ColumnToSort);
for (int i = 0; i < ColIndexSorts.Count; i++)
{
this.Sort(new GridSort(ColIndexSorts[i].SortOrder, ColIndexSorts[i].ColumnSortIndex));
}
}
}
目前这个结果的问题是当你选择了五列后,ColIndexSorts列表中包含了五列排序的数据;但是,由于 for
循环的运行方式,它按升序/降序正确排序,但它仅按列表中的最后排序排序。
我觉得这个问题的解决方案是对要执行的排序列表中的每个排序,记住每次排序后的行顺序,然后对该数据执行额外的排序。
你需要排序稳定。如果您使用的不是,请使用另一个,例如,linq 在 IEnumerable 上提供了一个。我承认这意味着对代码进行相当大的更改,因为您需要在 datagridview 之外进行排序并仅分配结果。顺便说一句,通过字符串表示来比较值对于数字而言远非完美。
编辑
我不知何故忽略了它是未绑定的。如果你想走这条路,你可以这样做:
private class GridSort : System.Collections.IComparer
{
List<GridSortData> ColIndexSorts = new List<GridSortData>();
public GridSort(List<GridSortData> ColIndexSorts)
{
this.ColIndexSorts = ColIndexSorts;
}
public int Compare(object x, object y)
{
FormGridRow FirstComparable = (FormGridRow)x;
FormGridRow SecondComparable = (FormGridRow)y;
for (int i = 0; i < ColIndexSorts.Count; ++i)
{
int index = ColIndexSorts[i].ColumnSortIndex;
object a = FirstComparable.Cells[index].Value;
object b = SecondComparable.Cells[index].Value;
int result = a.ToString().CompareTo(b.ToString());
if (result != 0)
{
if (ColIndexSorts[i].SortOrder == SortOrder.Ascending)
{
return result;
}
else
{
return -result;
}
}
}
return 0;
}
}
您必须将所有列的 SortMode 设置为程序化并处理 ColumnHeaderMouseClick,但我想您已经知道了。
我希望能够按 x 列对数据进行排序,其中 x 不是常数。
上下文:我有一个 DataGridView(未绑定),其中有许多行。因为我想按不止一列排序,所以我创建了一个 class 实现 IComparer 以对网格行进行排序。我已经完成了对单个列进行排序的工作,但是我不确定现在如何更改此 class 以允许对大于 1.
的多个列进行排序我之前看到的很多答案都提供了对两列或三列进行排序的示例,但是这些似乎是比较 A->B,然后是 B->C 等等。我正在寻找稍微更有活力的东西。
示例:
- 用户点击第4列;数据按记录的顺序排序 第 4 列;
- 用户然后点击第 6 列;数据按以下顺序排序 第 4 列中的记录然后第 6 列;
- 用户点击第2列;数据是 按第 4 列 THEN 第 6 列 THEN 第 2 列中的记录顺序排序;
等等
我目前的情况如下:
public class FormGrid : DataGridView
{
List<GridSortData> ColIndexSorts = new List<GridSortData>();
private class GridSortData
{
public int ColumnSortIndex;
public System.Windows.Forms.SortOrder SortOrder;
}
private class GridSort : System.Collections.IComparer
{
private static int SortOrder = 1;
private int SortingColumn;
public GridSort(System.Windows.Forms.SortOrder sortOrder, int ColumnToSort)
{
SortingColumn = ColumnToSort;
SortOrder = sortOrder == System.Windows.Forms.SortOrder.Ascending ? 1 : -1;
}
public int Compare(object x, object y)
{
FormGridRow FirstComparable = (FormGridRow)x;
FormGridRow SecondComparable = (FormGridRow)y;
int result = 1;
result = FirstComparable.Cells[SortingColumn].Value.ToString().CompareTo(SecondComparable.Cells[SortingColumn].Value.ToString());
return result * SortOrder;
}
}
private void TSortGrid(int ColIndexToSort, MouseButtons MouseButton)
{
GridSortData ColumnToSort = new GridSortData();
ColumnToSort.ColumnSortIndex = ColIndexToSort;
if (MouseButton == System.Windows.Forms.MouseButtons.Left)
{
ColumnToSort.SortOrder = System.Windows.Forms.SortOrder.Ascending;
}
else
{
ColumnToSort.SortOrder = System.Windows.Forms.SortOrder.Descending;
}
ColIndexSorts.Add(ColumnToSort);
for (int i = 0; i < ColIndexSorts.Count; i++)
{
this.Sort(new GridSort(ColIndexSorts[i].SortOrder, ColIndexSorts[i].ColumnSortIndex));
}
}
}
目前这个结果的问题是当你选择了五列后,ColIndexSorts列表中包含了五列排序的数据;但是,由于 for
循环的运行方式,它按升序/降序正确排序,但它仅按列表中的最后排序排序。
我觉得这个问题的解决方案是对要执行的排序列表中的每个排序,记住每次排序后的行顺序,然后对该数据执行额外的排序。
你需要排序稳定。如果您使用的不是,请使用另一个,例如,linq 在 IEnumerable 上提供了一个。我承认这意味着对代码进行相当大的更改,因为您需要在 datagridview 之外进行排序并仅分配结果。顺便说一句,通过字符串表示来比较值对于数字而言远非完美。
编辑
我不知何故忽略了它是未绑定的。如果你想走这条路,你可以这样做:
private class GridSort : System.Collections.IComparer
{
List<GridSortData> ColIndexSorts = new List<GridSortData>();
public GridSort(List<GridSortData> ColIndexSorts)
{
this.ColIndexSorts = ColIndexSorts;
}
public int Compare(object x, object y)
{
FormGridRow FirstComparable = (FormGridRow)x;
FormGridRow SecondComparable = (FormGridRow)y;
for (int i = 0; i < ColIndexSorts.Count; ++i)
{
int index = ColIndexSorts[i].ColumnSortIndex;
object a = FirstComparable.Cells[index].Value;
object b = SecondComparable.Cells[index].Value;
int result = a.ToString().CompareTo(b.ToString());
if (result != 0)
{
if (ColIndexSorts[i].SortOrder == SortOrder.Ascending)
{
return result;
}
else
{
return -result;
}
}
}
return 0;
}
}
您必须将所有列的 SortMode 设置为程序化并处理 ColumnHeaderMouseClick,但我想您已经知道了。