8

对于我(或者可能是其他任何人)来说,拥有一个我需要迭代然后与属性列表交互的对象列表并不少见。我使用嵌套循环,如下所示:

IList<T> listOfObjects;
IList<TProperty> listOfProperties;

foreach (T dataObject in listOfObjects)
{
    foreach (TProperty property in listOfProperties)
    {
        //do something clever and extremely useful here
    }
}

这是这个问题的时间和性能测试模式吗?或者有什么更高效、更优雅、或者只是简单有趣的东西(当然仍然是可读和可维护的)?

上面的代码不会让我微笑。有人可以帮我的循环带来一些快乐吗?

谢谢!

更新:我在最积极的意义上使用“书呆子”这个词。作为维基百科定义的一部分,它“指的是一个热情地追求智力活动的人”。我所说的“代码书呆子”是指关注不断提高自己作为程序员的人,寻找新的、新颖的、优雅的快速、可维护和美观的编码方式!他们很高兴能离开 VB6,并希望聪明的人批评他们的代码并帮助他们使自己变得聪明。(注意:他们也喜欢造以 -ify 结尾的新词)。

最后说明:

感谢 Dave R、Earwicker 和 TheSoftwareJedi 让我走上了 Linq 之路。这正是我正在寻找的那种快乐代码!

4

8 回答 8

8

嵌套循环当然没有错。它们速度快、可读性强,并且自软件开发迈出第一步以来就一直存在。

当您想要在迭代集合时执行操作时,您可能会发现 LINQ 将是一个有趣的探索途径:

http://msdn.microsoft.com/en-us/vcsharp/aa904594.aspx

您将限制自己使用更高版本的框架(3.5 及更高版本),但实际上您可能会发现函数式编程方法非常优雅。当你走这条路时,其他语言特性会发挥作用,包括 lambdas 和匿名方法,它们本身就很吸引人。

祝你好运,我希望你在路上玩得开心 - 这是一个很好的方法:)

于 2008-12-13T16:15:26.883 回答
8

看起来您正在尝试笛卡尔连接两个列表,并应用 where 子句。这是一个简单的示例,显示了执行此操作的 Linq 语法,我认为这是您正在寻找的。list1 和 list2 可以是任何 IEnumerable,您的 where 子句可以包含更详细的逻辑,并且在您的 select 子句中您可以抽出您需要的内容。

        var list1 = Enumerable.Range(1, 100);
        var list2 = Enumerable.Range(1, 100);

        foreach (var item in from a in list1
                             from b in list2
                             where a % b == 0
                             select new { a, b })
        {
            Console.WriteLine(item);
        };

性能将与您发布的内容相同 - 不想在这方面误导。我确实更喜欢这种 Linq 语法。

于 2008-12-13T17:07:54.543 回答
5
foreach (var pair in from obj in listOfObjects
                     from prop in listOfProperties  
                     select new {obj, prop})
{
   Console.WriteLine(pair.obj + ", " + pair.prop);
}
于 2008-12-13T16:59:48.043 回答
3

如果您需要对每个对象和每个属性都做某事,那么没有太多工作要做。您可能能够做一些语法上令人愉悦的事情,但没有办法绕过这项工作。

如果您只处理对象和/或属性的子集,请过滤它(使用 linq to objects,如果您正在使用 .net 3.5)!

您可能会喜欢使用Filter/Map/Reduce来为您的集合提供更好的语法来执行集合操作。

于 2008-12-13T16:04:16.830 回答
2
Action<T, TProp> somethingClever = //your clever method

listOfObjects
  .SelectMany(
    o => listOfProperties,
    (o, p) => new {o, p})
  .ToList()
  .ForEach(x => somethingClever(x.o, x.p));
于 2008-12-15T17:27:54.300 回答
2

虽然我确实喜欢 Linq 解决方案的优雅,但我认为我的建议是将内部循环提取到方法中;您的代码最终看起来像:

foreach(dataObject in listOfObjects)
    DoSomethingCleverWithProperties(dataObject, listOfProperties);

这对我来说更易于维护。

于 2008-12-15T17:39:38.707 回答
0

在这种情况下,我们通常从过滤我们感兴趣的部分开始。你的块 dosomethingclever() 通常开始于

foreach (T dataObject in listOfObjects)
{    
  foreach (TProperty property in listOfProperties)    
  {
    if (property.something == "blah") 
    { // OK, we found the piece we're interested in...

      // do something clever...

    }
  }
}

这就是 LINQ 是你的朋友的地方,它允许你用一个 select 语句替换你的循环。当然,您可能仍需要对结果集进行迭代。

这里有大量样品

于 2008-12-13T16:01:48.033 回答
0

我喜欢 Ayende 的管道和过滤器,但它比用于简单循环的内置 LINQ 的代码要多得多(我假设问题中的代码示例很简单)。

于 2008-12-15T17:35:24.627 回答