How to find N highest numbers in array? - c#

I needed to write a function that finds N highest numbers in an array.
I tried nothing. Don't even know where to start.
public int marathon(int input1,int input2, int[] input3)
{
// this is the function, ignore first input its not relevant input 2 is
// N(How much highest numbers you want from array )
}
If you put 2 as input2 and array looks like this {1,2,3,4} output will be 3 and 4

A little lambda will do the trick.
var top = new[] { 1, 2, 3, 4 }.OrderByDescending(num => num).Take(N);

By LINQ: Simply sort the array and take the first N items. Example of an extension method to do that:
public static class ExtensionMethods
{
public static IEnumerable<T> TakeHighests<T>(this IEnumerable<T> collection, int count)
{
return collection.OrderByDescending(i => i) // Sort the enumerable (arrays are also enumerables). Use OrderBy() for N lowest items
.Take(count) // Take only `count` items
}
}
Sample using of taking 2 highest values:
int[] arr = ...;
int[] twoHighests = arr.TakeHighests(2).ToArray();

Related

Find the major element of the array

I'm stuck in this logic and I don't know how to solve it, I have the following question:
"Given a nums array of size n, return the majority element, that is, the element that appears the most times in your array."
And I have this code base:
`using System;
using System.Text.RegularExpressions;
public class Program
{
public static void Main(String[] args)
{
int n = int.Parse(Console.ReadLine());
int[] num = new int[n];
for (int i = 0; i < n; i++)
{
num[i] = int.Parse(Console.ReadLine());
}
Console.WriteLine(MajorityElement(num));
}
public static int MajorityElement(int[] nums)
{
int major = nums[0];
int count = 1;
for (int i = 0; i < nums.Length; i++)
{
if ( )
{
major = nums[i];
count++;
}
else
{
if (major == nums[i])
{
count++;
}
else
{
count--;
}
}
}
return major;
}
}`
But I can't think of what the logic of the first IF would be.
How would that logic be in this question? And how would I solve it?
A succinct but inefficient way to solve this is like so:
int major = nums.ToLookup(n => n).MaxBy(item => item.Count()).Key;
How does this work?
nums.ToLookup(n => n)
This uses Enumerable.ToLookup() to create a lookup table.
The lookup table will contain one entry for each unique number in the array.
Each entry will consist of a key (which is the number) and a list of all the numbers with the same value.
The n => n part selects the lookup key from each value. In this case they are the same, but usually it would be used to select some property from a class that you were creating a lookup for.
That is, given this list (the numbers can be in any order):
int[] nums = { 1, 2, 2, 3, 3, 3 };
Then the lookup table will have 3 elements (one for each unique number in the list) as follows:
[1] = {1}
[2] = {2, 2}
[3] = {3, 3, 3}
Note that the numbers in the square brackets are NOT indices - they are keys. They do not have to be integers; they could be strings, for example.
I think you will already be able to see how inefficient this really is! We shouldn't need to store a list of all the matching numbers just to obtain a count of them. Nevertheless, let's carry on with the explanation.
.MaxBy(item => item.Count())
This selects the maximum element of the lookup table according to each element's item.Count() which is the count of all the items for each element. In the example above, you can see that [1] has a count of 1, [2] has a count of 2 and [3] has a count of 3.
.Key
Once we've selected the maximum element in the lookup table according to the count, we just access the key for that element. Remember that the keys for the lookup tables are the integers that we've counted. The key of the element with the most items, therefore, is the number we're looking for.
A much more efficient approach: Use a Dictionary<Tkey, TValue>
We can use a dictionary to count the number of unique items. The dictionary keys will be the unique integer values in the list, and the dictionary value for each key will be the number of occurrences of that key.
var dict = new Dictionary<int, int>();
foreach (int value in nums)
{
if (dict.ContainsKey(value))
++dict[value];
else
dict[value] = 1;
}
int major = dict.MaxBy(kvp => kvp.Value).Key;
This is much easier to understand. It goes through each number in the input and if it is not already in the dictionary, it adds a value of 1 to the dictionary. (This is of course the initial count.) If the number is already in the dictionary, it instead increments the value - i.e. it increments the count of occurrences of that number.
Finally the code selects the dictionary element with the highest value (i.e. highest repeat count) and selects the key for that value (which will be the number that was repeated that many times).

How to return true when comparing arrays with same items but in random positions?

Compare two arrays.
Return true if first array has same items as second array, even if they are in different positions.
Here are two possible arrays:
int[] arrayA = { 1, 2, 3 };
int[] arrayB = { 3, 2, 1 };
I can only find if arrayB has a single number in arrayA.
You could use the SequenceEqual method (LINQ).
bool areEqual = arrayA.OrderBy(n => n).SequenceEqual(arrayB.OrderBy(n => n));
One method to solve this would be create a HashSet<int> from each array, then use .SetEquals(HashSet<int> hashSet) to check if they have the same values.
public static bool CompareArrays(int[] array1, int[] array2)
{
// Create sets using Linq
HashSet<int> set1 = array1.ToHashSet();
HashSet<int> set2 = array2.ToHashSet();
// Compare the sets with .SetEquals()
return set1.SetEquals(set2);
}

Range operator in C# for arrays

I have a 3D array int array
arr1 = new int[2,2,2];
I'd like to create another array, this time 2D, which would be a part of the arr1.
Sudo code:
arr2 = arr1[..,..,2]
.. means all elements
(create 2D array from arr1 for trird dimension (rank) index equals 2)
But it looks like there is no a range operator for arrays in C#. Am I right, or I overlooked something?
In other languages thre are some range operators marking all elements, for example: .. or :
I'd like to avoid iterate over arr1 array.
Strange that Google brings you to such an old question, but there are now range operators (..) for C# 8+
For example:
var testArray = new[] { a, b, c, d, e, f };
var a = testArray[..]; // gets all elements (a,b,c,d,e,f)
var b = testArray[0..3]; // gets first 3 elements (a,b,c)
var c = testArray[3..5]; // gets elements 3 and 4 (d,e)
var d = testArray[^3..]; // gets all elements starting from 3
// but count starts from the end, that is testArray.Length - 3 (d,e,f)
See more examples here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/ranges
You can write your own extension
public static void getRange(this int[] array, int start, int end) {
//your for loop
}
Then use arr1.getRange(1,2)
But there is no builtin operator.

C# 3 dimensional array

I want to store ARRAY from 3 dimensional array into buildingCostIds, but it says I MUST have 3rd number.
public static int[, ,] buildingCost = { {{0,1,2},{5,5,5}}};
public static void addBuilding(int[] ids, int[] amounts, int buildingId)
{
int[] buildingCostIds = buildingCost[buildingId, 0, *];
}
*I need third number here, but I don't want it because it will extract just number, I want whole array!
PROBLEM SOLVED, solution:
public static Array extractArray(int dim1, int dim2)
{
int[] tempArray = { };
for (int number=0;number<=2; number++)
{
tempArray[number] = buildingCost[dim1, dim2, number];
}
return tempArray;
}
This might be simpler if you use an array-of-arrays, or jagged array [][][] like
int[][][] buildingCost = new int[2][][];
Then you can access buildingCost[buildingId, 0] which is an array of ints.
There is a related question here
EDIT
Be aware the "problem solved" you added to the question duplicates the data, so you may run out of memory if you keep doing this.
Consider using a List of Lists of Lists and lazy evaluating what you need.
Try This
int[, ,] array3D = new int[3,3,3]

LINQ query and sub-query enumeration count in C#?

suppose I have this query :
int[] Numbers= new int[5]{5,2,3,4,5};
var query = from a in Numbers
where a== Numbers.Max (n => n) //notice MAX he should also get his value somehow
select a;
foreach (var element in query)
Console.WriteLine (element);
How many times does Numbers is enumerated when running the foreach ?
how can I test it ( I mean , writing a code which tells me the number of iterations)
It will be iterated 6 times. Once for the Where and once per element for the Max.
The code to demonstrate this:
private static int count = 0;
public static IEnumerable<int> Regurgitate(IEnumerable<int> source)
{
count++;
Console.WriteLine("Iterated sequence {0} times", count);
foreach (int i in source)
yield return i;
}
int[] Numbers = new int[5] { 5, 2, 3, 4, 5 };
IEnumerable<int> sequence = Regurgitate(Numbers);
var query = from a in sequence
where a == sequence.Max(n => n)
select a;
It will print "Iterated sequence 6 times".
We could make a more general purpose wrapper that is more flexible, if you're planning to use this to experiment with other cases:
public class EnumerableWrapper<T> : IEnumerable<T>
{
private IEnumerable<T> source;
public EnumerableWrapper(IEnumerable<T> source)
{
this.source = source;
}
public int IterationsStarted { get; private set; }
public int NumMoveNexts { get; private set; }
public int IterationsFinished { get; private set; }
public IEnumerator<T> GetEnumerator()
{
IterationsStarted++;
foreach (T item in source)
{
NumMoveNexts++;
yield return item;
}
IterationsFinished++;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public override string ToString()
{
return string.Format(
#"Iterations Started: {0}
Iterations Finished: {1}
Number of move next calls: {2}"
, IterationsStarted, IterationsFinished, NumMoveNexts);
}
}
This has several advantages over the other function:
It records both the number of iterations started, the number of iterations that were completed, and the total number of times all of the sequences were incremented.
You can create different instances to wrap different underlying sequences, thus allowing you to inspect multiple sequences per program, instead of just one when using a static variable.
Here is how you can estimate a quick count of the number of times the collection is enumerated: wrap your collection in a CountedEnum<T>, and increment counter on each yield return, like this --
static int counter = 0;
public static IEnumerable<T> CountedEnum<T>(IEnumerable<T> ee) {
foreach (var e in ee) {
counter++;
yield return e;
}
}
Then change your array declaration to this,
var Numbers= CountedEnum(new int[5]{5,2,3,4,5});
run your query, and print the counter. For your query, the code prints 30 (link to ideone), meaning that your collection of five items has been enumerated six times.
Here is how you can check the count
void Main()
{
var Numbers= new int[5]{5,2,3,4,5}.Select(n=>
{
Console.Write(n);
return n;
});
var query = from a in Numbers
where a== Numbers.Max (n => n)
select a;
foreach (var element in query)
{
var v = element;
}
}
Here is output
5 5 2 3 4 5 2 5 2 3 4 5 3 5 2 3 4 5 4 5 2 3 4 5 5 5 2 3 4 5
The number of iteration has to be equal to query.Count().
So to the count of the elements in the result of the first query.
If you're asking about something else, please clarify.
EDIT
After clarification:
if you're searching for total count of the iteration in the code provided, there will be 7 iterations (for this concrete case).
var query = from a in Numbers
where a== Numbers.Max (n => n) //5 iterations to find MAX among 5 elements
select a;
and
foreach (var element in query)
Console.WriteLine (element); //2 iterations over resulting collection(in this question)
How many times does Numbers is enumerated when running the foreach
Loosely speaking, your code is morally equivalent to:
foreach(int a in Numbers)
{
// 1. I've gotten rid of the unnecessary identity lambda.
// 2. Note that Max works by enumerating the entire source.
var max = Numbers.Max();
if(a == max)
Console.WriteLine(a);
}
So we enumerate the following times:
One enumeration of the sequence for the outer loop (1).
One enumeration of the sequence for each of its members (Count).
So in total, we enumerate Count + 1 times.
You could bring this down to 2 by hoisting the Max query outside the loop by introducing a local.
how can I test it ( I mean , writing a code which tells me the number
of iterations)
This wouldn't be easy with a raw array. But you could write your own enumerable implementation (that perhaps wrapped an array) and add some instrumentation to the GetEnumerator method. Or if you want to go deeper, go the whole hog and write a custom enumerator with instrumentation on MoveNext and Current as well.
Count via public property also yields 6.
private static int ncount = 0;
private int[] numbers= new int[5]{5,2,3,4,5};
public int[] Numbers
{
get
{
ncount++;
Debug.WriteLine("Numbers Get " + ncount.ToString());
return numbers;
}
}
This brings the count down to 2.
Makes sense but I would not have thought of it.
int nmax = Numbers.Max(n => n);
var query = from a in Numbers
where a == nmax //notice MAX he should also get his value somehow
//where a == Numbers.Max(n => n) //notice MAX he should also get his value somehow
select a;
It will be iterated 6 times. Once for the Where and once per element for the Max.
Define and initialize a count variable outside the foreach loop and increment the count variable as count++ inside the loop to get the number of times of enumeration.

Categories