2

I am trying to find the Occurrences of a Maximum value in Integer Array.

e.g.

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

Here, the Max 3 is repeated twice and so the expected output is 2.

This works, I am getting count as 2 as the max value 3 occurred twice in the array

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++;
}

Output: 2 //occurrenceCount

With Linq it's more simple,

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

Output: 2 //occurrenceCount

Now without Linq, Is there any simplified or efficient way to do this?

Hary
  • 5,690
  • 7
  • 42
  • 79
  • 1
    you want to know how to max and count with more efficiency? – Drag and Drop Oct 18 '18 at 09:23
  • Yes, Want to know max and that max occurrences in the array – Hary Oct 18 '18 at 09:25
  • 2
    Which do you want: Simplified or efficient? There is always a trade-off. If you make a solution that only goes through the list once, it will be more efficient, but probably more complex. – Palle Due Oct 18 '18 at 09:30
  • 1
    [Max and GetCount](https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,121902bcb741dfe1) reference here. There is a foreach in both maybe you can refactor them in a smart way. – Drag and Drop Oct 18 '18 at 09:31
  • @PalleDue, Nice query, I prefer efficient way then. Is that the linq query in the quesiton is not efficient? – Hary Oct 18 '18 at 09:35
  • @auburg, Not a performance but still wondering to know the other possible ways off Linq – Hary Oct 18 '18 at 09:40

5 Answers5

4

At least, you can merge the two first arrays. I would still use the Linq solution. It is clearer. If you really want to talk about performance read Which is faster? first.

So here is a O(n) solution:

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!

  • Note that you should handle the case where you array is empty.
aloisdg
  • 22,270
  • 6
  • 85
  • 105
1

I did not use the linq. I used 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

No Linq and No 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++;
            }
go..
  • 958
  • 7
  • 15
1

Based on both implementation of Max and GetCount on Enumerable you can simply factorise by adding one test in the foreach of the Max like :

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");
}

The cool part is that it's easy to make it more generik like :

public static int CountMax<TSource>(this IEnumerable<TSource> source) where TSource : IComparable
Drag and Drop
  • 2,672
  • 3
  • 25
  • 37
  • Same logic than mine but slower. You can skip the first element. See my answer. – aloisdg Oct 18 '18 at 09:48
  • @aloisdg, yep same logic but with some fail safe and handeling enumerable, work on object that implement IComparable. From the System.LinQ implementation. It took just a bit more time to write and test with int and custom object – Drag and Drop Oct 18 '18 at 09:51
  • OP knows that it will use an array. At least switch to IReadOnlyList or IList. For the safety, yes OP should handle empty arrays. – aloisdg Oct 18 '18 at 09:54
  • @aloisdg, they both implement IEnumerable. So up to the one using the extention method to pass the type he want. For performance they should be the "same", it won't be noticable (tested: tenth of a nano secound on 10^6 element). I'm not trying to tell one is better than the other. From my side, I had fun looking for source and reading them a bit. – Drag and Drop Oct 18 '18 at 09:58
1

You can try more flexible approach:

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;
        }
    }
}
apocalypse
  • 5,764
  • 9
  • 47
  • 95
1
 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;
Khurram Ali
  • 1,659
  • 4
  • 20
  • 37