【问题标题】:Something like a VLOOKUP类似 VLOOKUP 的东西
【发布时间】:2013-09-20 20:28:58
【问题描述】:

我正在尝试合并两个不同对象的列表,其中特定字段 (employeeID) 等于另一个列表中的特定字段 [0,0]。我的代码如下所示:

int i = Users.Count() - 1;
int i2 = oracleQuery.Count() - 1;
for (int c = 0; c <= i; c++)
{
    for (int d = 0; d <= i2; d++)
    {
        if (Users[c].getEmployeeID().ToString() == oracleQuery[d][0,0].ToString())
        {
            Users[c].setIDMStatus(oracleQuery[d][0,1].ToString());
        }
    }
}

这行得通……但似乎效率不高。有什么更高效的代码建议最终会导致用户列表包含来自 oracleQuery 列表的新信息?

【问题讨论】:

  • 你的数据源是什么?甲骨文关系型数据库? P.s 你正在寻找一个 INNER JOIN 它将构成数据库查询的一部分。
  • 我的数据源是一个 Oracle 数据库和来自 Active Directory 的数据。

标签: c# performance


【解决方案1】:

您可以使用Enumerable.Join 的连接:

var matches = Users.Join(oracleQuery, 
                         u => u.getEmployeeId().ToString(), 
                         oq => oq[0,0].ToString(), 
                         (u,oc) => new { User = u, Status = oc[0,1].ToString() });

foreach(var match in matches)
    match.User.setIDMStatus(match.Status);

请注意,如果 getEmployeeId() 和 oracleQuery 的 [0,0] 元素属于同一类型,则可以消除 ToString() 调用。

【讨论】:

    【解决方案2】:

    就效率而言,我唯一注意到的是您使用了 Enumerable.Count() 方法,该方法在您在 for 循环中再次显式循环之前枚举结果。我认为 LINQ 实现将摆脱通过结果来计算元素的方式。

    我不知道你对使用LINQ QUERY EXPRESSIONS 有什么感觉,但这是我最喜欢的:

    var matched = from user in Users
                  join item in oracleQuery on user.getEmployeeID().ToString() equals item[0,0].ToString()
                  select new {user = user, IDMStatus = item[0,1] };
    
    foreach (var pair in matched) 
    {
         pair.user.setIDMStatus(pair.IDMStatus);
    }
    

    您还可以使用嵌套的 foreach 循环(如果有多个匹配项并且 set 被多次调用):

    foreach (var user in Users) 
    {
         foreach (var match in oracleQuery.Where(item => user.getEmployeeID().ToString() == item[0,0].ToString()) {
             user.setIDMStatus(match[0,1]);
         }
    }
    

    或者如果肯定只有一场比赛:

    foreach (var user in Users) 
    {
        var match = oracleQuery.SingleOrDefault(item => user.getEmployeeID().ToString() == item[0,0].ToString()); 
        if (match != null) {
            user.setIDMStatus(match[0,1]);
        }
    }
    

    我认为您编写的内容没有任何真正的效率问题,但您可以将其与 LINQ 中的实现进行基准比较。我认为使用foreachLinq query expression 可能会使代码更易于阅读,但我认为效率没有问题。您还可以使用 LINQ 方法语法编写 LINQ 查询表达式,就像在另一个答案中所做的那样。

    【讨论】:

    • 感谢史蒂夫提供的额外方法。我会做一个 foreach 语句,但由于某种原因(很可能是用户错误),它不想这样做。关于枚举的一些事情... 耸耸肩 一个奇怪的问题 - 该查询中的 select 子句不会生成新对象而不是更改现有对象吗? (只是好奇。我真的不知道。)
    • 那种。这将创建一个新的匿名对象,其中包含对现有对象的引用(除非它们是值类型,在这种情况下它们将被复制)。编译器有可能优化对象创建,但可能不会。最大的节省是您在代码中循环了两次……对 Count() 扩展方法的调用将枚举结果。然后,你显式地循环它。使用 Linq 语法(我和 Copsey 的实现是一样的,只是我使用查询语法,而 Copsey 使用方法语法),只有一个枚举。
    【解决方案3】:

    如果数据来自数据库,您可以在那里进行联接。否则,您可以对这两个列表进行排序并执行比现在更快的合并连接。

    但是,自从 C# 引入 LINQ 以来,有很多方法可以在代码中执行此操作。只需使用 linq 查找即可加入/合并列表。

    【讨论】:

      猜你喜欢
      • 2011-06-16
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多