【问题标题】:Best way to check values from a list that are not contained in another list. (Performance Testing)检查列表中未包含在另一个列表中的值的最佳方法。 (性能测试)
【发布时间】:2017-06-21 18:11:18
【问题描述】:

我在检查哪些对象在一个列表中但不在另一个列表中的各种方法之间执行了一些性能测试。 而且我得出了一个我没想到的结果,使用 lambda 执行相同操作的平均时间在 while、for、foreach 和 lambda 之间最高。

使用的代码:

// Object
public class ComplexObject
{
    public int Number { get; set; }
    public char Character { get; set; }
}

// Lists
private readonly List<ComplexObject> _complexList1 = new List<ComplexObject>();
private readonly List<ComplexObject> _complexList2 = new List<ComplexObject>();

/* Fills in lists with numbers from 0 to 100000 and characters from 0 to 50.
 * The first list contains 10000 records and a second list contains 1000 records. */
private void FillLists()
{
    var rnd = new Random();
    for (int i = 0; i < 100000; i++)
    {
        _complexList1.Add(new ComplexObject
        {
            Number = rnd.Next(5000),
            Character = (char)rnd.Next(50)
        });
    }
    for (int i = 0; i < 1000; i++)
    {
        _complexList2.Add(new ComplexObject
        {
            Number = rnd.Next(5000),
            Character = (char)rnd.Next(50)
        });
    }
}

// For
public void ExecuteFor()
{
    var result = new List<ComplexObject>();
    for (int countList2 = 0; countList2 < _complexList2.Count; countList2++)
    {
        bool found = false;
        for (int countList1 = 0; countList1 < _complexList1.Count; countList1++)
        {
            if (_complexList2[countList2].Number == _complexList1[countList1].Number &&
                _complexList2[countList2].Character == _complexList1[countList1].Character)
            {
                found = true;
                break;
            }
        }

        if (!found)
            result.Add(_complexList2[countList2]);
    }
}

// Foreach
public void ExecuteForeach()
{
    var result = new List<ComplexObject>();
    foreach (ComplexObject object2 in _complexList2)
    {
        bool found = false;
        foreach (ComplexObject object1 in _complexList1)
        {
            if (object2.Number == object1.Number &&
                object2.Character == object1.Character)
            {
                found = true;
                break;
            }
        }

        if (!found)
            result.Add(object2);
    }
}

// Lambda
public void ExecuteLambda()
{
    var result =
        _complexList2.Count(
            l2 => _complexList1.All(l1 => l2.Number != l1.Number || l2.Character != l1.Character));
}

使用 StopWatch 测量时间,每个循环类型运行 10 次,取平均执行时间,结果如下:

对于:10.163.836 平均刻度
Foreach:8.747.627 平均刻度
Lambda:14.326.094 平均滴答声

问题是:
还有其他方法可以解决我的问题吗?
Lambda 真的比 foreach 之类的普通循环花费更多时间吗?

【问题讨论】:

  • 这里似乎没有问题。如果您正在寻求实现目标的最高效方法......好吧,您面前有经验数据。
  • 我不明白这个问题。您似乎已经完成了基准测试。
  • 我注意到的一件事是您没有为 Random 实例使用种子值。这将导致每次运行测试时创建不同的列表。因此,如果您想要比较结果,您需要确保只调用一次 FillLists,然后将结果用于所有不同的实现。
  • 另外,您在这里比较的是苹果和梨,例如,您的 lambda 方法不会填充列表,而其他方法则可以。
  • 对不起,我忘了说明我的问题。问题已编辑,谢谢。

标签: c# performance loops lambda foreach


【解决方案1】:

Lambda 真的比 foreach 之类的普通循环花费更多时间吗?

查看here 了解为什么通常会出现这种情况。
here 看到一些异常。

【讨论】:

    【解决方案2】:

    您可以尝试使用Except 扩展方法,该方法将返回两个序列的列表项差异:

    List<ComplexObjects> _onlyInList1 = _complexList1.Except(_complexList2);
    

    https://msdn.microsoft.com/en-us/library/bb300779(v=vs.110).aspx

    【讨论】:

    • 这个表格不起作用,我测试了你建议和反转的方式,在这两种情况下,列表都返回了所有记录。我想她比较的是对象而不是值。
    • 您可能需要使用其他版本的 except 方法并提供您自己的自定义 EqualityComparer,如下所示:msdn.microsoft.com/en-us/library/bb336390(v=vs.110).aspx
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 2021-04-30
    相关资源
    最近更新 更多