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}");
}
}
}
}
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;
}
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}");
}
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();
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.
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}");
}
}
Related
How can I display only 3 consecutive numbers for example in my code below I only want it to return 4, as that appears 3 times.
9 is 4 times so do not want that and 7 is twice so not what want that.
The code I currently have display 9
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var adjacentDuplicateNumbers = intArray
.Skip(1)
.Where((value, index) => value == intArray[index])
.Distinct();
var enumerable = adjacentDuplicateNumbers as int[] ?? adjacentDuplicateNumbers.ToArray();
if (enumerable.Any())
{
Console.WriteLine("{0} is a consecutive number and is repeated 3 times.", enumerable.First());
}
else
{
Console.WriteLine("no consecutive number found.");
}
Using the extension method of this post: LINQ to find series of consecutive numbers
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
{
T prev = seq.First();
List<T> list = new List<T>() { prev };
foreach (T item in seq.Skip(1))
{
if (condition(prev, item) == false)
{
yield return list;
list = new List<T>();
}
list.Add(item);
prev = item;
}
yield return list;
}
Usage:
var res = intArray.GroupWhile((a, b) => a == b).
Where(x => x.Count() == 3).Select(x => x.First());
Sometimes a simple foor loop is enough (and should be faster than linq)
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var minus2 = intArray[0];
var minus1 = intArray[1];
var result = new List<int>();
for(int i = 2; i < intArray.Length; i++)
{
var current = intArray[i];
if(minus2 == minus1 && minus1 == current)
{
result.Add(current);
}
minus2 = minus1;
minus1 = current;
}
var results = intArray.Distinct()
.ToDictionary(k => k, v => intArray.Count(x => x == v))
.Where(x => x.Value == 3)
.Select(x => x.Key);
Take the district elements in the array. Use these as keys in a dictionary that map to the number of occurrences of this key in the original array. Use Where to only select pairs that match the required count (3). Use Select to return the resulting keys - in this example only 4.
How do I return a list of the 3 lowest values in another list. For example, I want to get the 3 lowest values like this:
in_list = [2, 3, 4, 5, 6, 1]
To this:
out_list: [2, 3, n, n, n, 1]
Maybe a function like this:
out_list = function(in_list, 3)?
in_list and ouput list is declared like this:
List<string> in_list = new List<string>();
List<string> out_list = new List<string>();
Can you help me developing a C# code for this? Further explanation can be given.
If you really want those weird n, there's this simple solution:
public static List<string> Function(List<string> inputList, int max)
{
var inputIntegers = inputList
.Select(z => int.Parse(z))
.ToList();
var maxAuthorizedValue = inputIntegers
.OrderBy(z => z)
.Take(max)
.Last();
return inputIntegers
.Select(z => z <= maxAuthorizedValue ? z.ToString() : "n")
.ToList();
}
public static void Main(string[] args)
{
List<string> in_list = new List<string> { "2", "3", "4", "6", "1", "7" };
var res = Function(in_list, 3);
Console.Read();
}
For your new requirement about duplicates, you could limit the max number of integer your return:
public static List<string> Function(List<string> inputList, int max)
{
var inputIntegers = inputList.Select(z => int.Parse(z)).ToList();
var maxAuthorizedValue = inputIntegers
.OrderBy(z => z)
.Take(max)
.Last();
// I don't really like that kind of LINQ query (which modifies some variable
// inside the Select projection), so a good old for loop would probably
// be more appropriated
int returnedItems = 0;
return inputIntegers.Select(z =>
{
return (z <= maxAuthorizedValue && ++returnedItems <= max) ? z.ToString() : "n";
}).ToList();
}
You need two queries, one to determine the lowest items and one to fill the result-list. You can use a HashSet for faster loookups:
var lowest = new HashSet<String>(in_list
.Select(s => new { s, val = int.Parse(s) })
.OrderBy(x => x.val)
.Take(3)
.Select(x => x.s));
List<string> out_list = in_list.Select(s => lowest.Contains(s) ? s : "n").ToList();
If you actually only want 3 and duplicates are possible this is the best i've come up with:
var lowest = new HashSet<String>(in_list
.Select(s => new { s, val = int.Parse(s) })
.Distinct()
.OrderBy(x => x.val)
.Take(3)
.Select(x => x.s));
List<string> out_list = in_list
.Select((str, index) => new { str, index, value = int.Parse(str) })
.GroupBy(x => x.str)
.SelectMany(g => lowest.Contains(g.Key)
? g.Take(1).Concat(g.Skip(1).Select(x => new { str = "n", x.index, x.value }))
: g.Select(x => new { str = "n", x.index, x.value }))
.OrderBy(x => x.index)
.Select(x => x.str)
.ToList();
You could use Aggregate to grab a Dictionary of each element with its corresponding number of allowed occurrences which you could then use to grab your values from the input list:
public static List<string> GetList(List<string> in_list, int max)
{
Dictionary<string, int> occurrences = new Dictionary<string, int>();
int itemsAdded = 0;
in_list.OrderBy(x => x).Aggregate(occurrences, (list, aggr) =>
{
if (itemsAdded++ < max)
{
if (occurrences.ContainsKey(aggr))
occurrences[aggr]++;
else
occurrences.Add(aggr, 1);
}
return list;
});
//occurrences now contains only each required elements
//with the number of occurrences allowed of that element
List<string> out_list = in_list.Select(x =>
{
return (occurrences.ContainsKey(x) && occurrences[x]-- > 0 ? x : "n");
}).ToList();
return out_list;
}
Suppose I have:
var correctOrder = new[] {2, 1, 0};
var actualPositionsFound = new[] {63,62,61];
How can I easily convert actualPositionsFound to a zero based sequence?
So if I had:
var actualPositionsFound = new[] {100,50,200];
I would like to end up with :
var result = new[] {1,0,2};
Update: In an attempt to make this clearer to avoid closing, what I believe is being asked for is to translate a list of numbers into another list of numbers representing the ascending order of the other list like a sort map, 0-based.
So { 16, 19, 2, 4 } would create a map { 2, 3, 0, 1 }, being 0-based.
If there are no duplicates:
var actualPositionsFound = new[] { 100, 50, 200 };
var indices = actualPositionsFound.OrderBy(n => n)
.Select((n, i) => new { n, i })
.ToDictionary(o => o.n, o => o.i);
var result = actualPositionsFound.Select(n => indices[n]).ToList();
Is it that you are looking for?
actualPositionsFound.Select((elem, idx) => new { elem, idx })
.OrderBy(wrap => wrap.elem)
.Select((wrap, idx) => new { wrap.idx, newIdx = idx })
.OrderBy(wrap => wrap.idx)
.Select(wrap => wrap.newIdx)
.ToArray();
actualPositionsFound
.OrderBy(x => x).ToList()
.Select(x => Array.IndexOf(actualPositionsFound,x)).ToArray();
This won't handle duplicates.
Is there a way that I could return duplicate values from an array in C#? also im looking to write a small algorithm that would return the most number of duplicate values in an array. for example
[1, 2,2,2 3,3] I need to return the duplicate values with the most number of occurrences and the number of occurrences as well.
I think I saw some post which said that It could be done using Linq but I have no clue what Linq is
Any help would be much appreciated.
Try this:
int[] data = new int[] { 1, 2, 2, 2, 3, 3 };
IGrouping<int, int> mostOccurrences = data
.GroupBy(value => value)
.OrderByDescending(group => group.Count())
.First();
Console.WriteLine("Value {0} occurred {1} time(s).", mostOccurrences.Key, mostOccurrences.Count());
Note that if multiple values occur the same number of times (such as if you added another 3 to that list), the above code will only list one of them. To handle that situation, try this:
int[] data = new int[] { 1, 2, 2, 2, 3, 3, 3 };
var occurrenceInfos = data
.GroupBy(value => value)
.Select(group =>
new {
Count = group.Count(),
Value = group.Key
}
);
int maxOccurrenceCount = occurrenceInfos.Max(info => info.Count);
IEnumerable<int> maxOccurrenceValues = occurrenceInfos
.Where(info => info.Count == maxOccurrenceCount)
.Select(info => info.Value);
foreach (int value in maxOccurrenceValues)
Console.WriteLine("Value {0} occurred {1} time(s).", value, maxOccurrenceCount);
Here's my take on this:
var data = new[] { 1, 2, 2, 2, 3, 3, };
var occurences =
data
.ToLookup(x => x)
.ToDictionary(x => x.Key, x => x.Count());
var mostOccurences =
occurences
.OrderByDescending(x => x.Value)
.First();
These will give you the following results:
i want to declare function in c# that accept an array an
return the Counts all the values of this array
like array_count_values in php
$array = array(1, 1, 2, 3, 3, 5 );
return
Array
(
[1] => 2
[2] => 1
[3] => 2
[5] => 1
)
what is the efficient way to do this ?
thanks
int[] array = new[] { 1, 1, 2, 3, 3, 5 };
var counts = array.GroupBy(x => x)
.Select(g => new { Value = g.Key, Count = g.Count() });
foreach(var count in counts) {
Console.WriteLine("[{0}] => {1}", count.Value, count.Count);
}
Alternatively, you can get a Dictionary<int, int> like so:
int[] array = new[] { 1, 1, 2, 3, 3, 5 };
var counts = array.GroupBy(x => x)
.ToDictionary(g => g.Key, g => g.Count());
Edit
Sorry, I see now that my previous answer was not correct. You are wanting to count each type of unique value.
You can use a Dictionary to store the value types:
object[] myArray = { 1, 1, 2, 3, 3, 5 };
Dictionary<object, int> valueCount = new Dictionary<object, int>();
foreach (object obj in myArray)
{
if (valueCount.ContainsKey(obj))
valueCount[obj]++;
else
valueCount[obj] = 1;
}
If you want to be able to count something besides ints try this
public static Dictionary<dynamic, int> Count(dynamic[] array)
{
Dictionary<dynamic, int> counts = new Dictionary<dynamic, int>();
foreach(var item in array) {
if (!counts.ContainsKey(item)) {
counts.Add(item, 1);
} else {
counts[item]++;
}
}
return counts;
}