Reputation: 221
I wrote this simple program:
class Program
{
static void Main(string[] args)
{
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int[] array = new int[numberOfElements];
for(int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i+1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for(int i = 0; i < array.Length; i++)
{
int count = 0;
for(int j = 0; j < array.Length; j++)
{
if(array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{array[i]} appears " + count + " times");
}
}
}
}
Is there any option to make the displayed values print only once? For example, if there are three occurrences - the message displays three times. Is it possible to make it display once when there are more occurrences though?
Upvotes: 20
Views: 1701
Reputation: 81493
You could use a GroupBy
instead of the for loop
Groups the elements of a sequence.
var results = array
.GroupBy(x => x)
.Select(x => new {Value = x, Count = x.Count()});
foreach(var g in results)
Console.WriteLine($"{g.Value} appears {g.Count} times");
Or another way it to use a HashSet
to keep track of what you have displayed. A HashSet
is basically a collection that contains no duplicate elements. The Add
methods returns true
if it can add an element or false
otherwise
returns true if the element is added to the HashSet object; false if the element is already present.
var hashSet = new HashSet<int>();
for (int i = 0; i < array.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
if (array[i] == array[j])
count++;
// Add to the hashset, if the add method returns true,
// it means the value was uniquely added, ergo you have not displayed yet
if (hashSet.Add(array[i]))
Console.WriteLine($"{array[i]} appears " + count + " times");
}
Or another approach is to use a Dictionary
. The premise is to iterate over the array, try an add each item to the dictionary with TryAdd
if it's already found increment the value
var dictionary = new Dictionary<int,int>();
foreach(var item in array)
if(!dictionary.TryAdd(item,1))
dictionary[item]++;
foreach(var item in dictionary)
Console.WriteLine($"{item.Key} appears {item.Value} times");
Upvotes: 12
Reputation: 2851
The first idea I had was the same of the comment from Jon Skeet, since the simplicity it implies.
The idea is to set null for the value we have already counted (matched).
From a developer point of view it is very simple and doesn't deviate too much from the OP's code.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
int?[] array = new int?[numberOfElements];
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
array[i] = int.Parse(Console.ReadLine());
}
for (int i = 0; i < array.Length; i++)
{
int count = 0;
int? current = array[i];
if (array[i] != null)
{
for (int j = 0; j < array.Length; j++)
{
if (current == array[j])
{
count++;
array[j] = null;
}
}
Console.WriteLine($"{current} appears " + count + " times");
}
}
int?[]
defines a nullable value type. Therefore each item in the array can have either a null or int value - documentation here.
Upvotes: 8
Reputation: 1317
You can also use Lookup here:
var sb = new StringBuilder();
foreach (var value in array.ToLookup(item => item))
{
sb.AppendLine($"{value.Key} appears " + value.Count() + " times");
}
Console.WriteLine(sb.ToString());
Upvotes: 3
Reputation: 509
In the inner loop, try to check if there were already any occurrences of the current element until you exceed the outer index.
for(int i = 0; i < array.Length-1; i++)
{
int count = 1;
bool appeared = false;
for(int j = 0; j < array.Length; j++)
{
// until we are not at the same index as the outer loop
// check if we haven't already met the current element
if(j < i)
{
if (array[i] == array[j])
{
// set current value appearance to true
// to know if current element should be displayed
appeared = true;
// break the loop because there is no sense of continuing
// current look
break;
}
}
// if we are ahead of outer index
// check if there are occurences of the element
else if(j > i)
{
if (array[i] == array[j])
count++;
}
}
// don't print the current element if it has appeared before
if(!appeared)
Console.WriteLine($"{array[i]} appears {count} times");
}
I believe there should be a more optimal solution, as this one's time complexity is linear... You can think of some optimization. For example, you can store occurred elements in the array and check through the array at each iteration, so you don't need to start the inner loop from the beginning, but instead start it from the outer loop's position + 1 but it's also not the best solution.
P.S check out about string interpolation, because you don't need to concatenate strings when you use it.
Upvotes: 3
Reputation: 37367
Other approach more suited for you would be too take only unique values from array, i.e.:
var unique = array.Distinct().ToArray();
for (int i = 0; i < unique.Length; i++)
{
int count = 0;
for (int j = 0; j < array.Length; j++)
{
if (array[i] == array[j])
{
count++;
}
}
Console.WriteLine($"{unique[i]} appears " + count + " times");
}
Upvotes: 3
Reputation: 20353
One simple way would be to swap your outer for
loop with a foreach
using a set to obtain distinct values.
So replace this:
for (int i = 0; i < array.Length; i++)
With this:
foreach (int i in new HashSet<int>(array))
And this:
if (array[i] == array[j])
With this:
if (i == array[j])
Upvotes: 4
Reputation: 3563
An approach using Dictionary
with O(n)
complexity.
Console.Write("Number of elements in the array: ");
int numberOfElements = int.Parse(Console.ReadLine());
var dictionary = new Dictionary<int, int>();
for (int i = 0; i < numberOfElements; i++)
{
Console.Write($"Element no {i + 1}: ");
var value = int.Parse(Console.ReadLine());
if (!dictionary.ContainsKey(value)) dictionary.Add(value, 0);
dictionary[value] = dictionary[value] + 1;
}
foreach (var item in dictionary)
{
Console.WriteLine($"{item.Key} appears {item.Value} times");
}
Upvotes: 5