【问题标题】:How to split One Datatable into Two (matched record) (unmatched record) using LINQ C#如何使用 LINQ C# 将一个数据表拆分为两个(匹配记录)(不匹配记录)
【发布时间】:2020-11-28 02:11:43
【问题描述】:

我有一个数据表,我需要将记录分为两个,数据表(匹配)和数据表(不匹配)。对于要匹配的记录,必须有两行具有相同的 RRN,并且这两个 AMOUNT 之和为零。

我使用下面的代码实现了这一点。

  if (InputCollection.Rows.Count > 0)
            {
                for (int i = InputCollection.Rows.Count - 1; i-- > 0;)
                {
                    var selectedRecord = InputCollection.Rows[i];
                    if (selectedRecord["RRN"].ToString() != "")
                    {
                        for (int j = 0; j < InputCollection.Rows.Count - 1; j++)
                        {
                            if (i != j)
                            {
                                var thisRecord = InputCollection.Rows[j];
                                var selectedRRN = selectedRecord["RRN"].ToString();
                                var thisRRN = thisRecord["RRN"].ToString();
                                if (selectedRRN.Trim() == thisRRN.Trim())
                                {
                                    if (Decimal.Parse(selectedRecord["AMOUNT"].ToString()) + Decimal.Parse(thisRecord["AMOUNT"].ToString()) == 0)
                                    {
                                        MatchedOutput.ImportRow(InputCollection.Rows[i]);
                                        MatchedOutput.ImportRow(InputCollection.Rows[j]);

                                        InputCollection.Rows.Remove(InputCollection.Rows[j]);
                                        InputCollection.Rows.Remove(InputCollection.Rows[i]);
                                        break;
                                    }

                                }
                            }


                        }

                    }

代码的问题是它太慢了。如何在 c# 中使用 LINQ 查询重写上面的代码?谢谢。

【问题讨论】:

  • PRN 列有什么类型?你一直在做ToString 和Trim。为什么数据在放入表格之前没有清除多余的空格?
  • 从Decimal.Parse 判断,Amount 列存储数字。但是,然后将此列设为typeof(decimal)。然后你就不需要解析了,代码会运行得更快。
  • Input Collection.Rows.Remove 减慢了很多,因为它会在删除一列后移动所有其他列。摆脱对这个方法的调用。
  • @AlexanderPetrov '为什么数据在放入表格之前没有清除多余的空格? ' 因为它来自一个 excel 文件

标签: c# linq loops datatable


【解决方案1】:

这并不简单,Linq 也不是完成的正确方法。见下面的代码

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("RRN", typeof(string));
            dt.Columns.Add("Amount", typeof(decimal));

            dt.Rows.Add(new object[] { 1, 1.0 });
            dt.Rows.Add(new object[] { 1, -1.0 });
            dt.Rows.Add(new object[] { 1, 2.0 });
            dt.Rows.Add(new object[] { 1, -2.0 });
            dt.Rows.Add(new object[] { 1, 3.0 });
            dt.Rows.Add(new object[] { 2, -3.0 });
            dt.Rows.Add(new object[] { 2, 1.0 });
            dt.Rows.Add(new object[] { 2, -1.0 });
            dt.Rows.Add(new object[] { 3, 1.0 });
            dt.Rows.Add(new object[] { 3, -1.0 });
            dt.Rows.Add(new object[] { 4, 1.0 });

            var groupRRN = dt.AsEnumerable().Select(x => new Match() { row = x, RRN = x.Field<string>("RRN"), amount = x.Field<decimal>("Amount"), matched = false }).GroupBy(x => x.RRN).ToList();

            DataTable matchedTable = dt.Clone();
            DataTable unmatchedTable = dt.Clone();

            foreach (var group in groupRRN)
            {
                for (int i = group.Count() - 1; i >= 1; i--)
                {
                    decimal amountI = group.Skip(i).First().amount;
                    for (int j = i - 1; j >= 0; j--)
                    {
                        Match matchJ = group.Skip(j).First();
                        if (!matchJ.matched)
                        {
                            decimal amountJ = matchJ.amount;
                            if (amountI + amountJ == 0)
                            {
                                group.Skip(i).First().matched = true;
                                group.Skip(j).First().matched = true;
                                break;
                            }
                        }
                    }
                }
                foreach (Match match in group)
                {
                    if (match.matched == true)
                    {
                        matchedTable.Rows.Add(match.row.ItemArray);
                    }
                    else
                    {
                        unmatchedTable.Rows.Add(match.row.ItemArray);
                    }
                }

            }

        }
    }
    public class Match
    {
        public DataRow row { get; set; }
        public Boolean matched { get; set; }
        public string RRN { get; set; }
        public decimal amount { get; set; }
    }
}

【讨论】:

  • 谢谢。我觉得这会比我目前的慢。一点洞察数据的本质。这个数据表有动态列,但都有 RRN 和 AMOUNT。最大列数可达 110,记录数可达 100 万。
  • 对于非常大的表,我的速度更快。你的算法是 N^2/2。我的我创建了一个哈希表(分组 RRN),它是 log(N) 来构建表。然后假设每个组的大小相同,则在每个组中搜索对会快得多。所以我的是 log(N) + (Log(N)^2/2) + Log(N) = 2Log(N) + Log(N)^2/2。所以 Log(N)^2 小于 N^2。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 2021-11-26
  • 2022-10-07
  • 1970-01-01
  • 1970-01-01
  • 2021-09-08
  • 1970-01-01
相关资源
最近更新 更多