English 中文(简体)
确定通用清单之间的差异
原标题:determining differences between generic lists

这个问题可能有10个重复,但我想知道是否有比目前更好的方法。这是我用来说明我如何确定差异的一个小例子:

        //let t1 be a representation of the ID s in the database.
        List<int> t1 = new List<int>() { 5, 6, 7, 8 };
        //let t2 be the list of ID s that are in memory.
        //these changes need to be reflected to the database.
        List<int> t2 = new List<int>() { 6, 8, 9, 10 };

        var hash = new HashSet<int>(t1);
        var hash2 = new HashSet<int>(t2);
        //determines which ID s need to be removed from the database
        hash.ExceptWith(t2); 
        //determines which ID s need to be added to the database.
        hash2.ExceptWith(t1);

        //remove contents of hash from database
        //add contents of hash2 to database

我要知道,我是否可以确定在一项行动中应该增加和删除什么,而不是目前我必须做的两种行动。 有没有办法提高这项行动的业绩?在数据库的实际状况中,有几十万个身份证。

<强度 > EDIT 或第二个问题,是否有一个 LINQ 查询,我可以直接在数据库上查询,这样我就可以提供新的IDs 列表,并自动删除/添加它本身? (使用 Mysql )

" 强烈的 " CLACLATION

<强 > EDIT2

SP Firedrake 的操作似乎比我的散列器版本更快, 但我不知道如何决定要添加哪些内容和从数据库中删除哪些内容。 是否有办法将这些信息包含在操作中?

t1.Union(t2).Except(t1.Intersect(t2))

<强 > EDIT3

我忘了,我忘记了这个说法实际上有延缓执行的问题, 尽管在案的任何人在想, 我用一个定制比较器和一个附加变量 来决定它来自哪个列表,解决了以前的问题。

最佳回答

最终, 您将使用一个完整的外部连结( 在 LINQ 世界上, 这是两个 GroupJoins ) 。 然而, 我们只关心两个表格中没有匹配记录的值。 右侧的值( 左外联队) 表示删除, 左侧的负值( 右外联队) 表示增加值 。 因此, 要让它这样工作, 我们只需要执行两个左外部连结( 切换第二个案例的输入以模仿右外部连结 ), 把它们组合在一起( 可以使用联盟, 但是没有必要, 因为无论如何我们会清除任何复制件 ) 。

List<int> t1 = new List<int>() { 5, 6, 7, 8 };
List<int> t2 = new List<int>() { 6, 8, 9, 10 };

var operations = 
    t1.GroupJoin(
        t2, 
        t1i => t1i, 
        t2i => t2i, 
        (t1i, t2join) => new { Id = t1i, Action = !t2join.Any() ? "Remove" : null })
    .Concat(
        t2.GroupJoin(
            t1, 
            t2i => t2i, 
            t1i => t1i, 
            (t2i, t1join) => new { Id = t2i, Action = !t1join.Any() ? "Insert" : null })
    .Where(tr => tr.Action != null)

这将为您提供选择的语句。 然后, 您可以将这些数据输入一个存储程序, 该程序可以删除表格中已经存在的值, 并添加其余的值( 或者两个列表来运行清除量和添加值 ) 。 无论是哪种方式, 仍然不是最清洁的方法, 但至少这可以让你思考 。

编辑:我最初的解决方案是根据需要什么行动来将这两个清单分开,这就是为什么它如此可怕的原因。 使用单行语也可以做同样的事情(但不在乎要采取什么行动 ), 尽管我认为你仍然会受到同样的问题的影响(使用LINQ [点数]而不是哈塞茨[哈什集 ) 。

// XOR of sets = (A | B) - (A & B), - being set difference (Except)
t1.Union(t2).Except(t1.Intersect(t2))

我敢肯定,它仍然会比使用油套慢, 但无论如何,给它一个机会。

编辑 : 是的, 速度更快, 因为它没有在收藏中做任何实际工作, 直到您在它上面加列( 要么在前方, 要么通过将其转换为具体的数据类型[ [IE: List< & gt;, Array, et] ) 。 仍然需要更多的时间才能解析要添加/ 删除哪些内容, 最终就是问题所在 。 我通过解开两个查询, 将它带入模拟世界( 通过 ToList () ), 使得它比散列版本慢 :

t1.Except(t2); // .ToList() slows these down
t2.Except(t1); 

诚实地说, 我会在 SQL 一边处理它。 在存储的 proc 中, 将所有值都存储在表格变量中, 并用另一列显示添加或删除( 根据表格中是否已经存在值) 。 然后您就可以重新加入此表格变量, 进行大宗删除/ 插入 。

编辑:我想扩大我的意思, 将完整的列表发送到数据库, 并在程序处理中处理:

var toModify = t1.Union(t2).Except(t1.Intersect(t2));
mods = string.Join(",", toModify.ToArray());
// Pass mods (comma separated list) to your sproc.

然后,在存储程序, 你会做到这一点:

-- @delimitedIDs some unbounded text type, in case you have a LOT of records
-- I use XQuery to build the table (found it s faster than some other methods)
DECLARE @idTable TABLE (ID int, AddRecord bit)
DECLARE @xmlString XML
SET @xmlString = CAST( <NODES><NODE>  + REPLACE(@delimitedIDs,  , ,  </NODE><NODE> ) +  </NODE></NODES>  as XML)

INSERT INTO @idTable (ID)
SELECT node.value( . , int ) 
FROM @xmlString.nodes( //NODE ) as xs(node)

UPDATE id
SET AddRecord = CASE WHEN someTable.ID IS NULL THEN 1 ELSE 0 END
FROM @idTable id LEFT OUTER JOIN [SomeTable] someTable on someTable.ID = id.ID

DELETE a
FROM [SomeTable] a JOIN @idTable b ON b.ID = a.ID AND b.AddRecord = 0

INSERT INTO [SomeTable] (ID)
SELECT id FROM @idTable WHERE AddRecord = 1

诚然, 这只是插入一些 ID, 它实际上不会添加任何其他信息 。 但是, 您仍然可以将 XML 数据传送到 sproc 中, 并以类似的方式使用 XQuery 来获取您需要添加的信息 。

问题回答

即使用Linq版本替换,你仍然需要两个操作。

s 假设您使用纯 SQL 来这样做 。

您可能需要两次询问:

  • one for removing the records
  • another one for adding them

使用 LINQ 代码, 它会比你的解算法复杂得多, 更不易读 。





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签