1

Hi I am trying to write a C# (Visual Studio) program for a function that takes integers in an array , and returns an array of integers that contains those integers which are most common in the input array.

sample in out -

[1,2,3,4,3,3,2,2,4] result = [2,3]
[1, 2, 3, 4, 5, 1, 6, 7, 1, 1] result = [1]
[1, 2, 3, 4, 5, 6, 7] result = [1, 2, 3, 4, 5, 6, 7]

I am almost there, but not getting expected results. Below is the code I wrote and I am a beginner.

namespace StringCommonElements
{
    class Program
    {
        static void Main(string[] args)
        {
            // Compute frequencies for this data.
            string[] values = { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" };
            // Get a list.
            List<string> valuesList = new List<string>(values);
            // Call our methods.
            var freqs = GetFrequencies(valuesList);
            DisplaySortedFrequencies(freqs);
        }
        static Dictionary<string, int> GetFrequencies(List<string> values)
        {
            var result = new Dictionary<string, int>();
            foreach (string value in values)
            {
                if (result.TryGetValue(value, out int count))
                {
                    // Increase existing value.
                    result[value] = count + 1;
                }
                else
                {
                    // New value, set to 1.
                    result.Add(value, 1);
                }
            }
            // Return the dictionary.
            return result;
        }
        static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
        {
            // Order pairs in dictionary from high to low frequency.
            var sorted = from pair in frequencies
                         orderby pair.Value descending
                         select pair;

            // Display all results in order.
            foreach (var pair in sorted)
            {
                Console.WriteLine($"{pair.Key} = {pair.Value}");
            }
        }

    }
}
1
  • I removed the visual-studio tags as these are reserved for questions about the development environment. Your question is however only about the language C#. Commented Apr 29, 2021 at 11:53

5 Answers 5

1

Here's how you can do that with Linq. That will group the numbers and find the count of each, then take all the ones that show up more than once. Then if the result is empty just return the original array because all the numbers are unique.

public int[] MostCommon(int[] numbers)
{
    var ans = numbers
        .GroupBy(x => x)            
        .Select(x => new {x.Key, x.Count}))
        .Where(x => x.Count > 1)
        .Select(x => x.Key)
        .ToArray();
    return ans.Length > 0 ? ans : numbers;
}
Sign up to request clarification or add additional context in comments.

Comments

1

In case you were just wondering how to make your existing code work, all you have to do is return (or output) the items that have the same frequency as the one with the maximum frequency.

For example:

var maxFrequency = sorted.First().Value;
       
Console.WriteLine("These items all occur the most:");
foreach (var pair in sorted)
{
    if (pair.Value < maxFrequency) break;
    Console.WriteLine($" - {pair.Key} = {pair.Value}");
}

Comments

1

To get the single most occurring number, you can use this LINQ expression (this will return 3, even though 2 appears just as much):

int appearsMost = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
  .GroupBy(x => x)
  .Select(x => (Key: x.Key, Items: x.ToList()))
  .OrderByDescending(x => x.Items.Count)
  .First().Key;

The select clause with the ToList() in between is to prevent having to count() the grouped items multiple times.

The following solution should give you the numbers that appear most. (this will return 2 and 3)

int[] appearMost = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
  .GroupBy(x => x)
  .Select(x => (Key: x.Key, Items: x.ToList()))
  .GroupBy(x => x.Items.Count)
  .OrderByDescending(x => x.Key)
  .First()
  .Select(x => x.Key)
  .ToArray();

If you want all numbers that appear more than once: (this will return 2,3,4,1)

int[] appearMoreThanOnce = new int[] { 1, 2, 3, 4, 3, 3, 2, 2, 4 }
  .GroupBy(x => x)
  .Select(x => (Key: x.Key, Items: x.ToList()))
  .OrderByDescending(x => x.Items.Count)
  .Where(x => x.Items.Count >= 1).Select(x => x.Key).ToArray();

In all cases, you can do the same by animals directly (only with small adjustments):

string[] animalsThatAppearMoreThanOnce = new string[] { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" }
  .GroupBy(x => x)
  .OrderByDescending(x => x.Count())
  .Where(x => x.Count() >= 1).Select(x => x.Key).ToArray();

// I added another cat, so this will return 'bird' and 'cat'.
string[] animalsThatAppearMost = new string[] { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat", "cat" }
  .GroupBy(x => x)
  .Select(x => (Key: x.Key, Items: x.ToList()))
  .GroupBy(x => x.Items.Count)
  .First()
  .Select(x => x.Key)
  .ToArray();

2 Comments

That's just the most common, the OP wants all numbers that appear more than once or all of them if no number appears more than once.
@juharr thanks for pointing that out, see the edit
0

Actually, your methods work. I think it is just a matter of display. In order to emulate the examples that you posted, I would just write the DisplaySortedFrequencies this way:

static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
            {
                // Order pairs in dictionary from high to low frequency.
                var sorted = from pair in frequencies
                             orderby pair.Value descending
                             select pair;

                // Display all results in order.
                int MaxNumValues = sorted.First().Value;
                foreach (var pair in sorted)
                {
                    int numValues = pair.Value;                    
                    if (numValues < MaxNumValues) //Show only the most predominant groups
                        break;
                    Console.WriteLine($"{pair.Key} = {numValues}");
                }
            }

In any case, if it is code that has to be performant, I would go for the solutions already posted that use Linq. I you don't want to use Linq for some reason, I would suggest to sort the items first and then count equal elements in a row instead of using a dictionary search for every element.

Comments

0

I have made a few changes to your code.

        static void Main(string[] args)
        {
            // Compute frequencies for this data.
            string[] values = { "bird", "cat", "bird", "dog", "bird", "man", "frog", "cat" };
            var freqs = GetFrequencies(values);
            DisplaySortedFrequencies(freqs);
        }


        static Dictionary<string, int> GetFrequencies(IEnumerable<string> values)
        {
            if (values == null) return new Dictionary<string, int>();

            var maxCount = 1;
            var result = new Dictionary<string, int>();

            foreach (string value in values)
            {
                if (result.TryGetValue(value, out int count))
                {
                    result[value] = count + 1;
                    if (maxCount < result[value])
                    {
                        maxCount = result[value];
                    }
                }
                else
                {
                    result.Add(value, 1);
                }
            }

            return result
                .Where(item => item.Value == maxCount)
                .OrderBy(item => item.Key)
                .ToDictionary(item => item.Key, item => item.Value);
        }

        static void DisplaySortedFrequencies(Dictionary<string, int> frequencies)
        {            
            foreach (var pair in frequencies)
            {
                Console.WriteLine($"{pair.Key} = {pair.Value}");
            }
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.