Array - find the number that is repeated most frequently [duplicate] - c#

This question already has answers here:
The Most frequent Number in an array
(11 answers)
How do I find duplicates in an array and display how many times they occurred?
(14 answers)
Closed 1 year ago.
I'm trying to know the number that is most present in one array.
Example:
8 4 3 8 4 4 1 5
In this case, I want the program to tell me the number is 4.
This is what I've written so far, but the console.Writeline returns an error system.32.
Can you help ?
int[] moda = new int[21];
for (int j = 0; j < avaliacoes.Length; j++)
{
int avaliacao = avaliacoes[j];
moda[avaliacao] = moda[avaliacao] + 1;
}
Console.WriteLine("\nA moda é{0}: ", moda);

Grouping with some ordering on group size should get the job done.
To summarize what I am doing I am grouping the array by there values, I then Emit that group into an anonymous type that will hold the key as well as the group count. Third I order by descending so we order or enumerable from high value to low, which will allow me to say the first element in the enumeration must be the top value (if not equal to the top value).
class Program
{
static void Main(string[] args)
{
var a = new[] { 8, 4, 3, 8, 4, 4, 1, 5 };
var mostPresent = a
.GroupBy(e => e)
.Select(e => new { Key = e.Key, Count = e.Count() })
.OrderByDescending(e => e.Count)
.FirstOrDefault();
Console.WriteLine(mostPresent);
}
}

There are many methods for doing that, here is one:
static void Main(string[] args)
{
// Create array
const int arrLength = 10;
int[] mainArray = new int[arrLength];
// Fill array with random numbers
Random randNum = new Random();
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = randNum.Next(10);
}
// Create a dictionary for counting
Dictionary<int, int> countDic = new Dictionary<int, int>();
foreach (var currentNumber in mainArray)
{
// If the current number has appeared before increase the count for that number
if (countDic.TryGetValue(currentNumber, out int _))
{
countDic[currentNumber]++;
}
// If it's first time current number has appeared set its count as one
else
{
countDic.Add(currentNumber, 1);
}
}
// Print frequency of numbers
foreach (var num in countDic)
{
Console.WriteLine($"{num.Key} appears {num.Value} times in the array!");
}
// Print the number which appears the most in the array
int maxNum = countDic.Aggregate((x, y) => x.Value > y.Value ? x : y).Key;
Console.WriteLine(maxNum);
Console.Read();
}
Ask me if there is anything that you can not understand in the solution

You can do that easily with LINQ. I'll explain what happens below:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
List<int> ints = new List<int> { 8, 4, 3, 8, 4, 4, 1, 5 };
var query = from i1 in ints
select new
{
number = i1,
count = ints.Where(i2 => i2 == i1).Count()
};
var most = query.OrderByDescending(x => x.count).First().number;
Console.WriteLine($"Number: {most}");
Console.ReadKey();
}
}
}
In the first query I iterate over all ints in the list and create an anonymous object with 2 properties 'number' and 'count'. The count contains the amount of ints in the list with the number of the first iteration.
In the second line the 'most'is selected by ordering the anonymous types in descending order on 'count' and taking the First item of that result. If you have more numbers in your array with the same number of entries you will get only the first one. So if '4' and 5' both are present 4 times it is not guaranteed which result you will get. It could be '4' but just as well '5'.

Related

Determine lower value from a list using LINQ in C#

I have a list with four double values in it
var numbers2 = new List<double>() { 2, 3, 9, 7 };
I need to get lower value between the first 2 indexes (2 and 3).
Similarly I need to get lower value between index 3 and 4 (9 and 7)
Is there a way in C sharp to determine this using LINQ?
Once I have the lower value from above list i.e 2 and 7; I need to pass these values in the below loop
for (int i = 0; i < 1; i++)
{
dac[i] = SetValue(lowerValue[j]);
}
if i == 0, I want lowerValue[j] = 2. If i == 1, I want lowerValue[j] = 7
Well as others have pointed out, it doesn't seem like there's any reason to use linq. But if you absolutely had to find some way to do it, then it's possible. I'll throw 3 options out, the last one being linq.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var numbers2 = new List<double>() { 2, 3, 9, 7 };
// you stated it's always 4 values. There's no reason to use linq. The optimal solution would
// be a variation of this (with some constant values instead of magic numbers)..
var first = Math.Min(numbers2[0],numbers2[1]);
var second = Math.Min(numbers2[2],numbers2[3]);
Console.WriteLine($"Lower values: {first},{second}");
// if it was an arbitry sized list (but always even count) you could use a iterator method
var listOfLowerValues = ToPairs(numbers2);
var values = string.Join(",", listOfLowerValues.Select(x => x.ToString()));
Console.WriteLine($"Lower values: {values}");
// finally if you absolutely had too, you can make it even more inefficient
// by using linq.
var indexes = Enumerable.Range(0, numbers2.Count);
var indexed = numbers2.Zip(indexes, (n,i) => (index: i, num: n));
var odd = indexed.Where(x => x.index%2 == 0).Select(x => x.num).ToArray();
var even = indexed.Where(x => x.index%2 > 0).Select(x => x.num).ToArray();
var lower = even.Zip(odd,(v1,v2)=> v1 < v2 ? v1 : v2);
var valuesByLinq = string.Join(",",lower.Select(x => x.ToString()));
Console.WriteLine($"Lower values: {valuesByLinq}");
}
static IEnumerable<double> ToPairs(IEnumerable<double> source)
{
int index = 0;
double previous = 0;
foreach(var n in source)
{
if(index++%2 > 0)
{
yield return (previous < n) ? previous : n;
}
else
{
previous = n;
}
}
}
}

C# Sort Numbers in a list [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'll explain my problem with an example: I want to sort the list(0,1,2,6,7) to the list(6,7,0,1,2), so every object in the list, that is say greater than 4 should be sorted in ascending order, beginning with the smallest and then everything that is smaller than 4, in ascending order, beginning with the smallest.
Make this comparer:
public class MyComparer : IComparer<int>
{
public int Divider { get; set; }
public MyComparer(int divider) { Divider = divider; }
public int Compare(int x, int y)
{
if (x < Divider && y > Divider) return 1;
if (x > Divider && y < Divider) return -1;
return x.CompareTo(y);
}
}
And then you can run this code:
List<int> list = new List<int> { 0, 1, 2, 6, 7 };
list = list.OrderBy(i => i, new MyComparer(4)).ToList();
Note it's not clear in the question how you want to handle the value 4 itself, if it should be first entry in the 6,7 group or the last entry in the 0,1,2 group. Based on what you expect to happen, one of the inequality comparison on each if() line above should include an =.
Doably with linq:
using System;
using System.Collections.Generic;
using System.Linq;
internal class Program
{
static void Main(string[] args)
{
List<int> myList = new List<int> { 0, 1, 2, 6, 7 };
var bigger4 = myList // from myList
.Where(item => item > 4) // filter all bigger 4
.OrderBy(i => i) // order them by value ascending
.ToList(); // make list to allow AddRange() later
// I am putting 4rs into this list
var smaller5 = myList // from myList
.Where(item => item <= 4) // filter all smalller equal 4
.OrderBy(i => i); // order them by value ascending
bigger4.AddRange(smaller5); // add to first list
// output as string with , between values:
Console.WriteLine(string.Join(",", bigger4)); // which smaller5 added into bigger4
Console.ReadLine();
}
}
Or put it in a Extensionmethod:
internal static class SillyThing
{
static public IList<int>
SortBigger_K_InFrontAnscendingThenAddSmallerEqual_K_Ascending(
this IList<int> list, int K)
{
var biggerK = list
.Where(item => item > K) // filter all bigger K
.OrderBy(i => i) // order them by value ascending
.ToList(); // make list to allow AddRange() later
// I am putting 4rs into this list
var smallerK = list
.Where(item => item <= K) // filter all smalller equal K
.OrderBy(i => i); // order them by value ascending
biggerK.AddRange(smallerK); // add to first list
return biggerK;
}
}
And call it like so:
var newList = "1,2,3,4,5,6,7,8,9,0,12,14,16,17,192,222,66,44,22,11".Split(',')
.Select(n => int.Parse(n))
.ToList();
Console.WriteLine(
string.Join(",", newList.
SortBigger_K_InFrontAnscendingThenAddSmallerEqual_K_Ascending(70)));
Console.ReadLine();
Disclaimer:
#JoelCoehoorn 's method is smater for reusability then using an extensionmethod that is that specific and SILLY.

Enumerator stuck in endless loop when removing excess items from a List

I have a script that takes an int[] array, converts it to a list and removes all further occurrences of the integers that already occurred at least 2 times.
The problem I have is that when it gets into the loop where I am checking the count of each integers occurrences, I am getting stuck in a loop.
EDIT: "What I left out was that the list has to remain in its original order so that excess numbers are removed from top down. Sorry if that confused those who already answered!
I thought that the changed number of the occursintegerOccurrence would act as a change of count for the while loop.
Any ideas on what I'm missing here? Aside from any discernible skill.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
public class Kata
{
public static void Main()
{
int[] arr = new int[] {1, 2, 1, 4, 5, 1, 2, 2, 2};
int occurrenceLimit = 2;
var intList = arr.ToList();
for (int i = 0; i < intList.Count; i++)
{
var occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);
do
{
occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);
foreach (var x in intList)
{
Console.WriteLine(x);
intList.Remove(intList.LastIndexOf(occurrenceLimit));
// Tried changing the count here too
occursintegerOccurrence = intList.Count(n => n == occurrenceLimit);
}
} while (occursintegerOccurrence > occurrenceLimit);
}
}
}
Here's a fairly concise version, assuming that you want to remove all instances of integers with a count in excess of 2, leaving the remainder of the bag in its original sequence, with preference to retention traversing from left to right:
int[] arr = new int[] {1, 2, 1, 4, 5, 1, 2, 2, 2};
var ints = arr.Select((n, idx) => new {n, idx})
.GroupBy(x => x.n)
.SelectMany(grp => grp.Take(2))
.OrderBy(x => x.idx)
.Select(x => x.n)
.ToList();
Result:
1, 2, 1, 4, 5, 2
It works by using the index overload of Select to project an anonymous Tuple and carrying through the original order to allow re-ordering at the end.
The cause of the endless loop is the line
intList.Remove(intList.LastIndexOf(occurrenceLimit));
..you are removing the value equals to the last occurence in the list of the occurrenceLimit value(=2), that it is "8" (the last index of the array counting from 0).
Since "8" it isn't present in the list, you don't remove anything and the loop permanence test doesn't ever change and so it is always verified and the loop never ends..
This method works for any values of occurrenceLimit but I think that the solution of StuartLC is better..
int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int?[] arr2 = new int?[arr.Length];
arr2.ToList().ForEach(i => i = null);
int occurrenceLimit = 2;
var ints = arr.GroupBy(x => x).Select(x => x.Key).ToList();
ints.ForEach(i => {
int ndx = 0;
for (int occ = 0; occ < occurrenceLimit; occ++){
ndx = arr.ToList().IndexOf(i, ndx);
if (ndx < 0) break;
arr2[ndx++] = i;
}
});
List<int?> intConverted = arr2.ToList();
intConverted.RemoveAll(i => i.Equals(null));
this may help you
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int occurrenceLimit = 2;
var newList = new List<Vm>();
var result=new List<Vm>();
for (int i = 0; i < arr.Length; i++)
{
var a = new Vm {Value = arr[i], Index = i};
result.Add(a);
}
foreach (var item in result.GroupBy(x => x.Value))
{
newList.AddRange(item.Select(x => x).Take(occurrenceLimit));
}
Console.WriteLine(string.Join(",",newList.OrderBy(x=>x.Index).Select(a=>a.Value)));
Console.ReadKey();
}
}
public class Vm
{
public int Value { get; set; }
public int Index { get; set; }
}
}
I did the following:
I created a Vm class with 2 props (Value and Index), in order to save the index of each value in the array.
I goup by value and take 2 ccurence of each values.
I order the result list base on the initial index.
It can be done by defining your own enumerator method, which will count already happened occurrences:
using System;
using System.Collections.Generic;
using System.Linq;
static class Test {
static IEnumerable<int> KeepNoMoreThen(this IEnumerable<int> source, int limit) {
Dictionary<int, int> counts = new Dictionary<int, int>();
foreach(int current in source) {
int count;
counts.TryGetValue(current, out count);
if(count<limit) {
counts[current]=count+1;
yield return current;
}
}
}
static void Main() {
int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int occurrenceLimit = 2;
List<int> result = arr.KeepNoMoreThen(occurrenceLimit).ToList();
result.ForEach(Console.WriteLine);
}
}
var removal = arr.GroupBy (a =>a ).Where (a =>a.Count()>2).Select(a=>a.Key).ToArray();
var output = arr.Where (a =>!removal.Contains(a)).ToList();
removal is an array of the items which appear more than twice.
output is the original list with those items removed.
[Update -- Just discovered that this handles the problem as originally specified, not as later clarified)
A single pass over the input array maintaining occurrence count dictionary should do the job in O(N) time:
int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int occurrenceLimit = 2;
var counts = new Dictionary<int, int>();
var resilt = arr.Where(n =>
{
int count;
if (counts.TryGetValue(n, out count) && count >= occurrenceLimit) return false;
counts[n] = ++count;
return true;
}).ToList();
Your code is stuck in an infinite loop because you are using List.Remove(), and the Remove() method removes an item by matching against the item you pass in. But you are passing in a list index instead of a list item, so you are getting unintended results. What you want to use is List.RemoveAt(), which removes an item by matching against the index.
So your code is stuck in an infinite loop because intList.LastIndexOf(occurrenceLimit) is returning 8, then Remove() looks for the item 8 in the list, but it doesn't find it so it returns false and your code continues to run. Changing this line:
intList.Remove(intList.LastIndexOf(occurrenceLimit));
to
intList.RemoveAt(intList.LastIndexOf(occurrenceLimit));
will "fix" your code and it will no longer get stuck in an infinite loop. It would then have the expected behavior of throwing an exception because you are modifying a collection that you are iterating through in a foreach.
As for your intended solution, I have rewritten your code with some changes, but keeping most of your code there instead of rewriting it entirely using LINQ or other magic. You had some issues:
1) You were counting the number of times occurenceLimit was found in the list, not the number of times an item was found in the list. I fixed this by comparing against intList[i].
2) You were using Remove() instead of RemoveAt().
3) Your foreach and do while need some work. I went with a while to simplify the initial case, and then used a for loop so I can modify the list (you cannot modify a list that you are iterating over in a foreach). In this for loop I iterate to the number of occurences - occurenceLimit to remove all but the first occurenceLimit number of them -- your initial logic was missing this and if your code worked as intended you would have removed every single one.
static void Main(string[] args)
{
int[] arr = new int[] { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
int occurrenceLimit = 2;
var intList = arr.ToList();
// Interestingly, this `.Count` property updates during the for loop iteration,
// so even though we are removing items inside this `for` loop, we do not run off the
// end of the list as Count is constantly updated.
// Doing `var count = intList.Count`, `for (... i < count ...)` would blow up.
for (int i = 0; i < intList.Count; i++)
{
// Find the number of times the item at index `i` occurs
int occursintegerOccurrence = intList.Count(n => n == intList[i]);
// If `occursintegerOccurrence` is greater than `occurenceLimit`
// then remove all but the first `occurrenceLimit` number of them
while (occursintegerOccurrence > occurrenceLimit)
{
// We are not enumerating the list, so we can remove items at will.
for (var ii = 0; ii < occursintegerOccurrence - occurrenceLimit; ii++)
{
var index = intList.LastIndexOf(intList[i]);
intList.RemoveAt(index);
}
occursintegerOccurrence = intList.Count(n => n == intList[i]);
}
}
// Verify the results
foreach (var item in intList)
{
Console.Write(item + " ");
}
Console.WriteLine(Environment.NewLine + "Done");
Console.ReadLine();
}
Here's a pretty optimal solution:
var list = new List<int> { 1, 2, 1, 4, 5, 1, 2, 2, 2 };
var occurrenceLimit = 2;
list.Reverse(); // Reverse list to make sure we remove LAST elements
// We will store count of each element's occurence here
var counts = new Dictionary<int, int>();
for (int i = list.Count - 1; i >= 0; i--)
{
var elem = list[i];
if (counts.ContainsKey(elem)) // If we already faced this element we increment the number of it's occurencies
{
counts[elem]++;
if (counts[elem] > occurrenceLimit) // If it occured more then 2 times we remove it from the list
list.RemoveAt(i);
}
else
counts.Add(elem, 1); // We haven't faced this element yet so add it to the dictionary with occurence count of 1
}
list.Reverse(); // Again reverse list
The key feature with list is that you have to traverse it backwards to have a possibility to remove items. When you traverse it as usual it will throw you an exception that explains that the list cannot modified. But when you are going backwards you can remove elements as you wish as this won't affect your further operations.

How to count how many times exist each number from int[] inside IEnumerable<int>?

I have array of ints(Call him A) and IEnumarable(Call him B):
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
I need to count how many times exist each number from A inside B and sum the result.
For example:
B - 1,2,4,8,289
A - 2,2,56,2,4,33,4,1,8,
result = 1+3+2+1+0
What is elegant way to implement it?
With LINQ it is easy:
int count = A
.Where(x => B.Contains(x))
.Count();
Counts how many times elements from A are contained in B.
As Yuval Itzchakov points out, this can be simplified like this:
int count = A.Count(x => B.Contains(x));
I need to count how many times exist each number from A inside B and sum the result.
You can get both the count and sum as follows
List<int> b = new List<int>() { 1,2,4,8,289 };
List<int> a = new List<int>() { 2,2,56,2,4,33,4,1,8 };
var subset = a.Where(i => b.Contains(i));
var count = subset.Count(); // 7
var sum = subset.Sum(); // 23
Note that I reuse the same Linq expression to get both the count and the sum.
One might be tempted to use a HashSet<int> in place of a List<int> because the .Contains operation is faster. However, HashSet is a set, meaning if the same number is added multiple times, only one copy of that number will remain in the set.
sweet and simple.. one line solution
why dont you try it..
int sum = 0;
A.ToList().ForEach(a=>sum +=B.Count(b=>b==a));
Console.Write(sum);
you can sweap the A/B it will still work
With Linq you can do like this
var B = new List<int>{ 1, 2, 4, 8, 289 };
var A = new List<int> { 2, 2, 56, 2, 4, 33, 4, 1, 8 };
var repetitionSum = B.Select(b => A.Count(a => a == b)).Sum(); //result = 7
And if you want, you can get the individual repetition list like this
var repetition = B.Select(b => A.Count(a => a == b)).ToList();
// { 1, 3, 2, 1, 0 }
It is not clear if you want to know the occurrences of each number or the final count (your text and your example code differ). Here is the code to get the number of appearances of each number
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
int[] a = new []{1,2,3};
int[] b = new []{1,2,2,3};
Dictionary<int, int> aDictionary = a.ToDictionary(i=>i, i => 0);
foreach(int i in b)
{
if(aDictionary.ContainsKey(i))
{
aDictionary[i]++;
}
}
foreach(KeyValuePair<int, int> kvp in aDictionary)
{
Console.WriteLine(kvp.Key + ":" + kvp.Value);
}
}
}

How to search for a number in a list of arrays of numbers based on the first index of each array using LINQ?

I have a list of arrays of numbers. I am searching for the two arrays where my search number falls between the numbers positioned in index 0. Then return the number positioned in index 1 from the second array. (Assume numbers in index 0 are sorted already and there are no duplicates)
My wrong solution for LINQPad:
The value of 'found' should be 3 because 9 falls between 4 & 10 in second and third array. Then I take the second found array and return 3 which is in index 1 of that array.
List<int[]> list = new List<int[]> { new[] { 1, 5 }, new[] { 4, 6 }, new[] { 10, 3} , new[] { 15, 8} };
int searchFor = 9;
int found = list.Where(n => searchFor >= n[0] && searchFor <= n[0]).Select(i => i[1]).FirstOrDefault();
found.Dump(); //should be 3 instead of 0.
Try this :
int found = list.Zip(list.Skip(1), (x, y) => x[0]<=searchFor&&y[0]>=searchFor?y[1]:0).FirstOrDefault(o=>o!=0);
Well my logic is a little different, but get the result you want. I would recommend just using a Dictionary if you are doing key-pair-value stuff like this. It makes things simpler in my opinion and if you have no repeating key's this should work fine.
// Use dictionary instead of array's if just using two int values
var dic = new Dictionary<int, int>();
dic.Add(1, 5);
dic.Add(4, 6);
dic.Add(10, 3);
dic.Add(15, 8);
int searchFor = 9;
// Don't need to find this really
int low = (from l in dic
where l.Key <= searchFor
select l.Key).Max();
// Just need this
int found = (from h in dic
where h.Key >= searchFor
select h.Value).Min();
Console.WriteLine("Low: " + low);
Console.WriteLine("Found: " + found);
How about
var found = list.First(l => l[0] > searchFor)[1];
It should do the trick as I can assume that list is ordered by each first element.
If not, then
var found = list.Orderby(l=>l[0]).First(l => l[0] > searchFor)[1];
should also work.
The expression in the where statement filters for arrays having the first element less or equal and greater or equal than 9. Since it can't be less and greater at the same time it actually filters for all arrays that have 9 as first element.
For the given data this results in an empty sequence. FirstOrDefault therefore returns the default (0 for integers).
You actually have to look for the first element greater or equal than 9:
int[] result = list.FirstOrDefault(arr => arr[0] >= searchFor);
if (result == null)
{
Console.WriteLine("Not found!");
}
else
{
Console.WriteLine(result[1]);
}

Categories

Resources