【问题标题】:Finding Occurance of Max Value in Array查找数组中最大值的出现
【发布时间】:2018-10-18 09:22:17
【问题描述】:

我正在尝试在整数数组中查找最大值的出现次数。

例如

int[] ar = [3, 1, 2, 3];

这里,Max 3 重复了两次,所以预期的输出是 2

这行得通,我得到计数​​为2,因为最大值3 在数组中出现了两次

var max = int.MinValue;
var occurrenceCount = 0;

foreach(var x in ar)
{
    if (x >= max) max = x;
}

foreach(var x in ar)
{
    if (x == max) occurrenceCount++;
}

输出:2 //occurrenceCount

Linq 更简单,

var occurrenceCount = ar.Count(x => x == ar.Max())

输出:2 //occurrenceCount

现在没有Linq,有没有简化或有效的方法来做到这一点?

【问题讨论】:

  • 您想知道如何更高效地最大化和计数吗?
  • 是的,想知道数组中的最大值和最大出现次数
  • 您想要哪个:简化还是高效?总是有一个权衡。如果您制定的解决方案只通过列表一次,它会更有效,但可能更复杂。
  • Max and GetCount 参考这里。两者都有一个 foreach,也许你可以用聪明的方式重构它们。
  • @PalleDue,很好的查询,我更喜欢高效的方式。是不是问题中的linq查询效率不高?

标签: c# linq max find-occurrences


【解决方案1】:

至少,您可以合并前两个数组。我仍然会使用 Linq 解决方案。它更清楚。如果您真的想谈论性能,请先阅读Which is faster?

所以这是一个 O(n) 的解决方案:

int[] ar = {3, 1, 2, 3, 3, 4, 4};
int max = ar[0];
var occurrenceCount = 1;

for(var i = 1; i < ar.Length; i++)
{
    if (ar[i] > max) {
	max = ar[i];
	occurrenceCount = 1;
    }
    else if (ar[i] == max) {
        occurrenceCount++;
    }
}

WriteLine(max);
WriteLine(occurrenceCount);

Try it online!

  • 请注意,您应该处理数组为空的情况。

【讨论】:

    【解决方案2】:

    基于 Max 的 implementation 和 Enumerable 上的 GetCount,您可以通过在 Max 的 foreach 中添加一个测试来简单地分解,例如:

    public static int CountMax(this IEnumerable<int> source)
    {
        if (source == null)
        {
            throw new ArgumentException();
        }
    
        int value = 0;
        bool hasValue = false;
        int count = 0;
    
        foreach (int x in source)
        {
            if (hasValue)
            {
                if (x > value)
                {
                    value = x;
                    count = 1;
                }
                else if (x == value)
                {
                    count++;
                }
            }
            else
            {
                value = x;
                count = 1;
                hasValue = true;
            }
        }
        if (hasValue)
        {
            return count;
        }
    
        throw new Exception("no elements");
    }
    

    很酷的部分是它很容易使它更通用:

    public static int CountMax<TSource>(this IEnumerable<TSource> source) where TSource : IComparable
    

    【讨论】:

    • 与我的逻辑相同,但速度较慢。您可以跳过第一个元素。看我的回答。
    • @aloisdg,是的,相同的逻辑,但有一些故障安全和处理可枚举,在实现 IComparable 的对象上工作。来自 System.LinQ 实现。用 int 和自定义对象编写和测试只花了一点时间
    • OP 知道它将使用一个数组。至少切换到 IReadOnlyList 或 IList。为了安全起见,是的,OP 应该处理空数组。
    • @aloisdg,他们都实现了 IEnumerable。所以最多使用扩展方法来传递他想要的类型。就性能而言,它们应该是“相同的”,不会引起注意(测试:10^6 元素上的十分之一纳秒)。我不是想告诉一个比另一个更好。从我的角度来看,我很高兴寻找源代码并阅读它们。
    【解决方案3】:

    我没有使用 linq。我用过 lamda :)

     int[] ar = new[] { 3, 1, 2, 3 };
    
    
            var result = ar.GroupBy(x => x) //values groups
            .Select(x => new
            {
                Number = x.Key,
                Count = x.Count()
            }).OrderByDescending(x => x.Count) //Short
            .FirstOrDefault(); //First Result
    
    
     result.Count // how many 
    
     result.Key   // max number
    

    没有 Linq 和没有 Lamda

     int[] ar = new[] { 3, 1, 2, 3 };
                Array.Sort(ar);
                Array.Reverse(ar);
                var maxValue = ar[0];
                var occurrenceCount = 0;
                foreach (var item in ar)
                {
                    if (item == maxValue)
                        occurrenceCount++;
                }
    

    【讨论】:

    • 它仍然是 Linq...事实上,如果没有 System.Linq,它将无法工作。这应该是一个提示;)
    【解决方案4】:

    您可以尝试更灵活的方法:

    using System.Collections.Generic;
    
    namespace ConsoleApp42
    {
        class Program
        {
            static void Main (string[] args)
            {
                var array = new int[] { 1, 2, 3, 1, 1, 4, 4, 4, 4, 1, 1, 1 };
                //var array = new string[] { "a", "b", "a", "a" };
    
                var result = array.MaxCount ();
            }
        }
    
        public static class Extensions
        {
            public static (long count, T max) MaxCount<T> (this IEnumerable<T> source, IComparer<T> comparer = null)
            {
                if (comparer is null) comparer = Comparer<T>.Default;
    
                (long count, T max) result = (0, default (T));
    
                foreach (var element in source)
                {
                    if (result.count == 0) // is first element?
                    {
                        result.max = element;
                        result.count = 1;
    
                        continue;
                    }
    
                    int compareResult = comparer.Compare (element, result.max);
    
                    if (compareResult == 0) // element == max
                    {
                        result.count++;
                    }
                    else if (compareResult > 0) // element > max
                    {
                        result.max = element;
                        result.count = 1;
                    }
                }
    
                return result;
            }
        }
    }
    

    【讨论】:

      【解决方案5】:
       int[] list = new int[] { 1, 1, 2, 3, 6, 7, 6, 6, 6, 8, 9 };
              Dictionary<int, int> occ = new Dictionary<int, int>();
              for (int i = 0; i < list.Length; i++)
              {
                  var val = list[i];
                  var count = 0;
                  for (int j = 0; j < list.Length; j++)
                  {
                      if (val == list[j])
                      {
                          count++;
                      }
                  }
                  occ.TryAdd(val, count);
              }
              var maxCount = occ.Values.Max();
              var repNumber = occ.FirstOrDefault(x => x.Value == maxCount).Key;
      

      【讨论】:

        猜你喜欢
        • 2019-10-27
        • 1970-01-01
        • 2012-08-14
        • 2011-04-29
        • 2013-06-22
        • 2021-04-02
        • 1970-01-01
        • 1970-01-01
        • 2021-09-15
        相关资源
        最近更新 更多