【问题标题】:Fastest way to count number of distinct elements in array计算数组中不同元素数量的最快方法
【发布时间】:2020-01-17 11:27:59
【问题描述】:

我有这样一类对象:

public class Individual
{
    public double[] Number { get; set; } = new double[2]{ 0.0, 0.0 };
}

我将这些类存储在字典列表中,并为 Individual.Number 提供值:

selection = List<Dictionary<int, Individual>>

现在,我必须计算Individual.Number(在整个列表中)的不同值的数量。到目前为止我所做的是:

selection.Values.SelectMany(list => list.Number).Distinct().Count();

我想知道这是否是最快的计数方法?如何提高性能?

谢谢,

【问题讨论】:

  • 你的方法很好。我建议避免使用microoptimizing,除非您遇到实际性能问题。

标签: c# arrays class dictionary


【解决方案1】:

Distinct() 方法在内部创建一个新的Set&lt;T&gt; 而不指定大小。

如果您对元素的数量有一个模糊的概念,这可以防止多次分配(和内存移动)。

因为你只想要 Count() 你可以直接包含它(Credits @TimSchmelter)。

    public static int OptimizedDistinctAndCount<TSource>(this IEnumerable<TSource> source, int numberOfElements) {
        if (source == null) throw Error.ArgumentNull("source");
        var set = new HashSet<TSource>(numberOfElements);
        foreach (TSource element in source) {
           set.Add(element);
        }
        return set.Count;
    }

然后你可以使用:

selection.Values.SelectMany(list => list.Number).OptimizedDistinctAndCount(123);

【讨论】:

    【解决方案2】:

    您对此有何看法?

    public class Individual
    {
      public double[] Numbers { get; set; }
      public Individual()
      {
        Numbers = new double[0];
      }
      public Individual(double[] values)
      {
        Numbers = values/*.ToArray() if a copy must be done*/;
      }
    }
    
    class Program
    {
      static void Main()
      {
        // Populate data
        var selection = new List<Dictionary<int, Individual>>();
        var dico1 = new Dictionary<int, Individual>();
        var dico2 = new Dictionary<int, Individual>();
        selection.Add(dico1);
        selection.Add(dico2);
        dico1.Add(1, new Individual(new double[] { 1.2, 1.3, 4.0, 10, 40 }));
        dico1.Add(2, new Individual(new double[] { 1.2, 1.5, 4.0, 20, 40 }));
        dico2.Add(3, new Individual(new double[] { 1.7, 1.6, 5.0, 30, 60 }));
        // Count distinct
        var found = new List<double>();
        foreach ( var dico in selection )
          foreach ( var item in dico )
            foreach ( var value in item.Value.Numbers )
              if ( !found.Contains(value) )
                found.Add(value);
        // Must show 12
        Console.WriteLine("Distinct values of the data pool = " + found.Count);
        Console.ReadKey();
      }
    }
    

    这种方法消除了一些调用方法的时间。

    进一步的优化将使用 for 循环而不是 foreach,并且可能使用链表而不是 List(更快但需要更多内存)。

    【讨论】:

      猜你喜欢
      • 2013-12-26
      • 1970-01-01
      • 2016-12-20
      • 2019-11-04
      • 1970-01-01
      • 2010-09-07
      • 2013-02-13
      • 2013-07-02
      • 2022-01-15
      相关资源
      最近更新 更多