【问题标题】:Fastest way to navigate and add items to two different lists导航和添加项目到两个不同列表的最快方式
【发布时间】:2011-10-06 14:00:10
【问题描述】:

我有 2 个不同类别的 2 个列表。为此,我们可以称它们为 Foo 和 Bar。 Foos 列表包含每个 Foo 所属的 Bars。 Bars 列表包含 Bar 所属的所有 Foo。

我需要一种快速有效的方式来循环浏览两个列表并将每个项目添加到另一个列表中。

我目前正在使用:

//  Add the List of Zones to the Vehicles
foreach (Foo foo in Program.data.Foos.list)
{
    foreach (Bar bar in Program.data.Bars.list)
    {
        bar.Foos.Add(foo);
        foo.Bars.Add(bar);
    }
} 

但是,对于我的数据集,我有 ~5000 Foos 和 ~5000 Bars。这需要大约 3 秒来迭代另一个最常见的 foreach 循环,而且似乎效率很低。

有没有更快的方法来做到这一点?可能与Linq?你们会建议什么来加快速度?还是我在速度方面碰壁了?

【问题讨论】:

    标签: c# linq list


    【解决方案1】:

    如果bar.Foos and foo.Bars 是属性,则在循环之前为它们进行初始分配

    var list1=bar.Foos; 
    var list2=foo.Bars;
    

    bar.Foosfoo.Bars 提供初始容量也很好。

    【讨论】:

    • 我的类已经初始化并且已经存在。我创建了所有的 Foos,然后创建了所有的 Bars。然后我需要将每个 Foo 添加到每个 Bar 的列表中,反之亦然。
    • 那么,只需将您的代码更改为“bar=new List(5000)”。这将减少内部重新分配。
    • 我明白你的意思,这将有助于填写我的压力数据,因为每个 Foo 将属于每个 Bar,反之亦然。但在现实世界的使用中,它们并不总是属于彼此。此外,我无法知道每个可以包含多少个,所以我不想硬限制一个大小,尽管它甚至超过了可能使用的范围。那么这有什么帮助呢?
    • @Nathan Raley,这只是一个“初始容量”,您可以添加比初始容量更多/更少的项目。 “list.Count”总是给出正确的项目计数。我用 100 万个字符串试了一下,发现速度提高了 30%。
    【解决方案2】:

    this question 中所述,您可以查看您正在执行的操作的渐近复杂度,看看您是否可以重新设计并以某种方式使用为这些操作提供较少渐近复杂度的集合类型,或者您可以尝试使用this question 中提到的任务并行库以某种方式在某些线程或进程之间分配工作。

    【讨论】:

    • 对我如何分割该操作有什么建议吗?我唯一能想到的就是拆分列表并为其中的 % 执行并行任务。
    • 有一个棘手的部分,你有 2 个具有 am:n 关系的列表,所以如果没有对内容的深入了解,就无法将这两个列表划分为“有意义的小桶”,你可以将两个列表划分为Z 部分并对所有部分进行交叉计算,但由于您需要与其他部分共享每个部分,因此工作量将增加 2*Z^2,这很快就会叠加起来。尽管如此,您仍然可以并行完成很多工作,但请记住列表将是不可变的,因此您需要保存以在所有任务完成后复制的单独结果列表。
    【解决方案3】:

    您也可以在 List 上使用 Union 扩展,因为只要您的对象具有可比性(或者您已覆盖 GetHashCode),它将避免重复

    bar.Foos = bar.Foos.Union(Program.data.Foos.list).ToList()
    

    【讨论】:

    • 你知道我在哪里可以找到 Union 的实现吗?我在 Foo 和 Bar 中的属性是 ILists,我还没有实现 Union。
    • 只需添加“使用 System.Linq”(我在 .NET 4 中尝试过),它就会加载扩展。
    • 没关系,在错误的列表中调用它。我做了一个 Foo.bars.Union(Program.data.bars.list) 但这并没有导致任何东西被发布到列表中。我无法通过将 Foo.bars = 设置为联合的结果来进行分配我得到了实现 IList 和 List 的自定义集合类型的错误 b/c
    • 联合是一个 IEnumerable 所以你可能需要添加: bar.Foos = bar.Foos.Union(Program.data.Foos.list).ToList()
    • 是的,问题在于它返回了一个通用列表。它不会让我将该列表转换为我的集合类型。如果我向我的集合类型添加一个属性以获取/设置我的集合中的私有 _list,它似乎可以工作。不过,我必须看看这是否对我的 NHibernate 映射有任何负面影响。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-25
    • 1970-01-01
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多