LINQ - 合并列表元素保留顺序(功能思维)

时间:2014-11-25 08:30:54

标签: c# vb.net linq

我有一个sql语句列表

List<IStatement>
  • 更新SET a.col1 = 1 FROM tableA a
  • 更新SET a.col2 = 2 FROM tableA a
  • 更新SET a.col3 = 3 FROM tableA a
  • 选择a.Col1,a.Col2,a.Col3 FROM tableA a
  • 更新b SET b.col1 = 1 FROM tableB b
  • 更新b SET b.col2 = 2 FROM tableB b
  • SELECT b.Col1,b.Col2 FROM tableB b

突出课程包括:

  • SelectStatement:IStatement
  • UpdateStatement:IStatement

UpdateStatement有一个

  • 返回From子句的GetFrom方法
  • 返回IEnumerable的GetSets方法
  • AddSet方法,它将新的Set表达式添加到现有的集合

我有一个IsEqualTo扩展方法来比较From子句

我正在尝试使用Linq Aggregate运算符将更新语句合并到单个更新语句中,同时保留顺序以便最终列表。

  • 更新SET a.col1 = 1,a.col2 = 2,a.col3 = 3 FROM tableA a
  • 选择a.Col1,a.Col2,a.Col3 FROM tableA a
  • 更新b SET b.col1 = 1,b.col2 = 2 FROM tableB b
  • SELECT b.Col1,b.Col2 FROM tableB b

我正在考虑使用聚合来尝试这样做 - 到目前为止我的代码是

Dim mergeUpdates = Function(statements As IList(Of IStatement), statement As IStatement)

                       If statements.Count = 0 Then Return statements.AddItem(statement)
                       If Not TypeOf statement Is UpdateStatement Then Return statements.AddItem(statement)

                       Dim u = DirectCast(statement, UpdateStatement)
                       Dim t = (From st In statements
                               Where TypeOf st Is UpdateStatement
                               Let uSt = DirectCast(st, UpdateStatement)
                               Where uSt.GetFrom.IsEqualTo(u.From)
                               Select uSt).First.AddSet(u.Set)

                       Return statements.AddItem(t)

                   End Function

 Return statements.Aggregate(New List(Of IStatement), Function(ss, s) mergeUpdates(ss, s)))

但现在我不确定Linq Aggregate是否是正确的方法。 (我知道上面的内容不完整)

我很感激任何指向正确(FP)方式的指示。

1 个答案:

答案 0 :(得分:1)

首先,您需要将相关的更新语句组合在一起:

var groupedStatements = statements
       .GroupBy(s=>new {IsUpdate= (s is UpdateStatement), From=s.GetFrom()});

GroupBy会将相关的更新语句分组,即使它们在列表中不是连续的。如果您只想对连续的语句进行分组,则需要替代GroupBy,例如thisthis

这假设所有IStatements都有一个GetFrom(),如果不是,你需要一些与?运算符相关的技巧。此外,它要求From类实现IEquatable,以允许GroupBy运算符检查相同的from子句。如果没有,则需要将from子句转换为字符串或其他内容,以便进行比较。

然后组合每个更新组的元素,并保持其他组不变

var combinedStatements = groupedStatements
        .SelectMany(group=>group.Key.IsUpdate 
            ? Enumerable.Repeat<IStatement>(new UpdateStatement (group.Key.From, group.Select(s=>s.GetSets())),1)
            : group.Select(s=>s);

在这里,您需要一种方法来创建一个新的UpdateStatement,就像一个构造函数,它接受一个from子句和一个IEnumerable的Set子句。 SelectMany将结果语句列表的列表折叠为单个语句列表。请注意,Enumerable.Repeat(s,1)用于创建只有一个元素的新IEnumerable。