【问题标题】:Why doesn't my DataTable.DefaultView.Sort sort things in order?为什么我的 DataTable.DefaultView.Sort 不按顺序排序?
【发布时间】:2019-07-24 13:46:46
【问题描述】:

所以我正在尝试对一些数据进行排序并打印出来,但DataTable.DefaultView.Sort 似乎并没有像我期望的那样工作。鉴于此数据:

Col1    Col2    Col3
2802    32      0
2802    80      3
2802    130     3
2802    40      0
2802    40      0
2802    35      0

并按“Col2”排序,我得到:

2802    130     3
2802    32      0
2802    35      0
2802    40      0
2802    40      0
2802    80      3

我写了一个简单的排名库来做我期望的事情 (DataTableRanker.Framework.Util),它在这个代码 sn-p 的下方,但它只按 1 列排序,我更喜欢使用 .Sort = Col1, Col2, Col3, 等:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using DataTableRanker.Framework.Util;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            DataTable testTable = new DataTable();
            testTable.Columns.Add("FacilityID");
            testTable.Columns.Add("FromDimensions");
            testTable.Columns.Add("FromAttributeName");

            DataRow dr1 = testTable.NewRow();
            dr1["FacilityID"] = "2802";
            dr1["FromDimensions"] = 4*8;
            dr1["FromAttributeName"] = 0;
            testTable.Rows.Add(dr1);

            DataRow dr2 = testTable.NewRow();
            dr2["FacilityID"] = "2802";
            dr2["FromDimensions"] = 8*10;
            dr2["FromAttributeName"] = 3;
            testTable.Rows.Add(dr2);

            DataRow dr3 = testTable.NewRow();
            dr3["FacilityID"] = "2802";
            dr3["FromDimensions"] = 10*13;
            dr3["FromAttributeName"] = 3;
            testTable.Rows.Add(dr3);

            DataRow dr4 = testTable.NewRow();
            dr4["FacilityID"] = "2802";
            dr4["FromDimensions"] = 4*10;
            dr4["FromAttributeName"] = 0;
            testTable.Rows.Add(dr4);

            DataRow dr5 = testTable.NewRow();
            dr5["FacilityID"] = "2802";
            dr5["FromDimensions"] = 4 * 10;
            dr5["FromAttributeName"] = 0;
            testTable.Rows.Add(dr5);

            DataRow dr6 = testTable.NewRow();
            dr6["FacilityID"] = "2802";
            dr6["FromDimensions"] = 5*7;
            dr6["FromAttributeName"] = 0;
            testTable.Rows.Add(dr6);

            DataTable copyTestTable;
            copyTestTable = testTable.Copy();
            copyTestTable.Columns.Add("Ranking");

            Console.Write("-- Not Sorted --");
            Console.WriteLine();

            foreach (DataRowView dr in testTable.DefaultView)
            {
                for (int i = 0; i < testTable.DefaultView.Table.Columns.Count; i++)
                    Console.Write(dr[i] + "\t");
                Console.WriteLine();
            }

            testTable.DefaultView.Sort = "FromDimensions";

            Console.Write("-- Sorted --");
            Console.WriteLine();
            foreach (DataRowView dr in testTable.DefaultView)
            {
                for (int i = 0; i < testTable.DefaultView.Table.Columns.Count; i++)
                    Console.Write(dr[i] + "\t");
                Console.WriteLine();
            }

            Console.Write("-- Ranked with System.Data --");
            Console.WriteLine();
            testTable.Columns.Add(new DataColumn("Rank", typeof(int)));
            int count = 1;
            foreach (DataRowView dr in testTable.DefaultView)
            {
                dr["Rank"] = count++;
            }

            foreach (DataRowView dr in testTable.DefaultView)
            {
                for (int i = 0; i < testTable.DefaultView.Table.Columns.Count; i++)
                    Console.Write(dr[i] + "\t");
                Console.WriteLine();
            }

            Console.Write("-- Ranked with DataTableRanker --");
            Console.WriteLine();

            DataTableSort u1 = new DataTableSort();
            u1.RankDataTable(ref copyTestTable, "FromDimensions", "Ranking");
            copyTestTable.DefaultView.Sort = "Ranking";
            foreach (DataRowView dr in copyTestTable.DefaultView)
            {
                for (int i = 0; i < copyTestTable.DefaultView.Table.Columns.Count; i++)
                    Console.Write(dr[i] + "\t");
                Console.WriteLine();
            }
        }
    }
}

这里是DataTableRanker.Framework.Util

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace DataTableRanker.Framework.Util
{
    public class DataTableSort
    {
        public void RankDataTable(ref DataTable toOperateDataTable, string sortByValue, string rankingValue)
        {
            // group data elements
            List<RankGroup> rgc = new List<RankGroup>();
            foreach (DataRow dr1 in toOperateDataTable.Rows)
            {
                RankGroup g1 = new RankGroup();
                foreach (DataRow dr2 in toOperateDataTable.Rows)
                {

                    if (dr1 != dr2 && dr2 != null)
                    {
                        if (!g1.Index.Contains(toOperateDataTable.Rows.IndexOf(dr1)))
                        {
                            g1.Index.Add(toOperateDataTable.Rows.IndexOf(dr1));
                            g1.Score = float.Parse((string)dr1[sortByValue]);
                        }

                        if ((float.Parse((string)dr1[sortByValue]) == float.Parse((string)dr2[sortByValue]) && !g1.Index.Contains(toOperateDataTable.Rows.IndexOf(dr2))))
                        {
                            g1.Index.Add(toOperateDataTable.Rows.IndexOf(dr2));
                            g1.Score = float.Parse((string)dr2[sortByValue]);
                        }                        
                    }

                }
                if (!ExistsIndexes(rgc, g1))
                    rgc.Add(g1);
            }

            List<RankGroup> sortedRankGroup = rgc.OrderByDescending(t => t.Score).ToList();

            int ranking = 1;
            foreach (RankGroup rg in sortedRankGroup)
            {
                foreach (int i in rg.Index)
                {
                    toOperateDataTable.Rows[i][rankingValue] = ranking;
                }
                ranking++;
            }            
        }

        bool ExistsIndexes(List<RankGroup> rgc, RankGroup rg)
        {
            foreach (RankGroup trg in rgc)
            {
                foreach (int i in rg.Index)
                {
                    if (trg.Index.Any(t => t == i))
                        return true;
                }
            }
            return false;
        }

        internal class RankGroup
        {
            // string sortByFiled;
            float score;
            List<int> indexes = new List<int>();
            int ranking;

            public float Score
            {
                get { return score; }
                set { score = value; }
            }

            public List<int> Index
            {
                get { return indexes; }
                set { indexes = value; }
            }

            public int Ranking
            {
                get { return ranking; }
                set { ranking = value; }
            }
        }
    }
}

非常感谢任何帮助或解释!

【问题讨论】:

  • 请确保您的问题是明确的。 “我认为应该的。”对那些想帮助你的人没有意义。请看:stackoverflow.com/help/dont-ask
  • 为什么不:DataTable sortedTable = testTable.AsEnumerable().OrderBy(x => x[1]).ThenBy(x => x[2]).CopyToDataTable();
  • @jdweng 好吧,这将由其他人维护,我不想让他们使用 lambdas
  • 它看起来被排序为文本而不是数字..不确定这是否有帮助。
  • 这可能与stackoverflow.com/questions/24053498/… 重复(未指定列类型)

标签: c# datatable system.data


【解决方案1】:

正如 cmets 中所建议的,排序顺序是基于字符串的。 1 在 3 之前,因此 130 出现在 31 之前。这是添加没有其他选项的新列时的默认行为

DataTable class documentation 的示例中,先看看创建列,然后设置它的数据类型。

column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
table.Columns.Add(column);

更新: 感谢 cmets 中的 ESG 指出 DataColumnCollection.Add 的重载也会采用类型。

【讨论】:

  • 如果你想稍微简化代码,Columns.Add 有一个重载类型
猜你喜欢
  • 2010-11-15
  • 1970-01-01
  • 2015-05-02
  • 2020-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多