This question already has answers here:
C# find biggest number
(7 answers)
Closed 9 years ago.
I have 3 values stored in the variables v, p, and k. I want to find the greatest among them. The values of the variables are: v = 3, p = 6, and k = 2.
The result should be the name of the variable that contains the maximum value—the text v, p, or k.
How can I do this?
Well, you just obviated every answer already posted by not clearly stating what you wanted the first time. You can extend the use of Enumerable.Max easily to give you what you now want:
string max =
new[] {
Tuple.Create(v, "v"),
Tuple.Create(p, "p"),
Tuple.Create(k, "k")
}.Max()
.Item2;
An alternative is:
string max = v >= p && v >= k ? "v" : p >= v && p >= k ? "p" : "k";
But do you see how much less readable that is than the first version?
The other answers are very good, but for the sake of completeness, I'd like to point out that for simplicity, you can also use Math.Max:
var max = Math.Max(Math.Max(v, p), k);
Update given your updated question, I'd recommend this:
var max = v > p ? v > k ? "V" : p > k ? "P" : "K" : p > k ? "P" : "K";
It's rather unwieldy, but it works (k wins ties with p or v, p wins ties with v).
var values = new List<int> { v, p, k };
var maxValue = values.Max();
Update, re your modified question: The variable names don't exist in the compiled IL code. Therefore you can't easily retrieve them.
But you can create a dictionary. Off the top of my head (I didn't actually try this, but it could be somewhat along these lines):
var dict = new Dictionary<string, int> {
{ "V", 3 }, { "P", 6 }, { "K", 2 }
};
var max = dict.Values.Max();
var relevantKey = dict
.Where(x => max.Equals(x.Value))
.Select(x => x.Key)
.FirstOrDefault()
Here is some hand-maded method, based on generics and Max from Enumerable:
public static T MaxVal<T>(params T[] items)
{
return items == null? default(T) : items.Max();
}
And for integers, for example, you can call it like this:
Console.WriteLine(MaxVal(4, 8, 15, 16, 42));
Related
This question already has answers here:
Find character with most occurrences in string?
(12 answers)
Closed 7 years ago.
I want to find the Mode in an Array. I know that I have to do nested loops to check each value and see how often the element in the array appears. Then I have to count the number of times the second element appears. The code below doesn't work, can anyone help me please.
for (int i = 0; i < x.length; i ++)
{
x[i]++;
int high = 0;
for (int i = 0; i < x.length; i++)
{
if (x[i] > high)
high = x[i];
}
}
Using nested loops is not a good way to solve this problem. It will have a run time of O(n^2) - much worse than the optimal O(n).
You can do it with LINQ by grouping identical values and then finding the group with the largest count:
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;
This is both simpler and faster. But note that (unlike LINQ to SQL) LINQ to Objects currently doesn't optimize the OrderByDescending when only the first result is needed. It fully sorts the entire result set which is an O(n log n) operation.
You might want this O(n) algorithm instead. It first iterates once through the groups to find the maximum count, and then once more to find the first corresponding key for that count:
var groups = x.GroupBy(v => v);
int maxCount = groups.Max(g => g.Count());
int mode = groups.First(g => g.Count() == maxCount).Key;
You could also use the MaxBy extension from MoreLINQ method to further improve the solution so that it only requires iterating through all elements once.
A non LINQ solution:
int[] x = new int[] { 1, 2, 1, 2, 4, 3, 2 };
Dictionary<int, int> counts = new Dictionary<int, int>();
foreach( int a in x ) {
if ( counts.ContainsKey(a) )
counts[a] = counts[a]+1
else
counts[a] = 1
}
int result = int.MinValue;
int max = int.MinValue;
foreach (int key in counts.Keys) {
if (counts[key] > max) {
max = counts[key];
result = key;
}
}
Console.WriteLine("The mode is: " + result);
As a beginner, this might not make too much sense, but it's worth providing a LINQ based solution.
x
.GroupBy(i => i) //place all identical values into groups
.OrderByDescending(g => g.Count()) //order groups by the size of the group desc
.Select(g => g.Key) //key of the group is representative of items in the group
.First() //first in the list is the most frequent (modal) value
Say, x array has items as below:
int[] x = { 1, 2, 6, 2, 3, 8, 2, 2, 3, 4, 5, 6, 4, 4, 4, 5, 39, 4, 5 };
a. Getting highest value:
int high = x.OrderByDescending(n => n).First();
b. Getting modal:
int mode = x.GroupBy(i => i) //Grouping same items
.OrderByDescending(g => g.Count()) //now getting frequency of a value
.Select(g => g.Key) //selecting key of the group
.FirstOrDefault(); //Finally, taking the most frequent value
This question already has answers here:
How to check if list contains another list in same order
(2 answers)
Closed 4 years ago.
Is there any elegant way in c# to check whether a List<T> contains a sub-List<T> similar to string.Contains(string)?
Let's say e.g. I want to test for example whether List A is contained in List B
List<int> A = new List<int>{ 1, 2, 3, 4, 3, 4, 5 };
List<int> B = new List<int>{ 3, 4, 5 };
important is that all elements have to match in exactly that order.
I know I could possibly do something like
bool Contains(List<Sampletype> source, List<Sampletype> sample)
{
// sample has to be smaller or equal length
if (sample.Count > source.Count) return false;
// doesn't even contain first element
if (!source.Contains(sample[0])) return false;
// get possible starts
// see https://stackoverflow.com/a/10443540/7111561
int[] possibleStartIndexes = source.Select((b, i) => b == sample[0] ? i : -1).Where(i => i != -1).ToArray();
foreach (int possibleStartIndex in possibleStartIndexes)
{
// start is too late -> can't match
if (possibleStartIndex + sample.Count - 1 > source.Count - 1) return false;
for (int index = possibleStartIndex; index < possibleStartIndex + sample.Count; index++)
{
// if one element does not match the whole sample doesn't match
if (source[index] != sample[index]) return false;
}
// if this is reached all elements of the sample matched
Debug.Log("Match found starting at index " + possibleStartIndex);
return true;
}
return false;
}
But I hope there is a better way to do so.
Here's a oneliner:
var result = A.Select(a => $"{a}").Aggregate((c, n) => $"{c};{n}").Contains(B.Select(b => $"{b}").Aggregate((c, n) => $"{c};{n}"));
It basically creates a string from each list, and checks whether the A string contains the B string. This way you won't just get a method like string.Contains, you actually get to use just that.
EDIT
Added separator to the string aggregations, as {1, 2, 3} would result in the same string as {1, 23}
EDIT 2
Re-adding my first approach which identifies if list B is present in list A, perhaps scattered, but still ordered:
var result = B.Intersect(A).SequenceEqual(B)
Essentially you want to slide over A and check each element of that window with the B. The last part is actually SequenceEqual and I do recommend to use it but this is just an alternative to explain the point:
bool equal = Enumerable.Range(0, A.Count() - B.Count() + 1)
.Select(i => A.Skip(i).Take(B.Count))
.Any(w => w.Select((item, i) => item.Equals(B[i])).All(item => item));
I know this question has been asked before, but the other questions are only about finding the CLOSEST. I dont want that. I need the LOWEST between two values. For example if this is the list:
Code from How to get the closest number from a List<int> with LINQ?:
List<int> numbers = new List<int>();
numbers.Add(2);
numbers.Add(5);
numbers.Add(7);
numbers.Add(10)
and the number to find is 9, I want it to return the 7 item, not 10 even though its closer. This code finds the closest, but any time I change it to find the lowest in the range it breaks for other situations where the inputted number is one of the numbers in the list(for example 7 or 10):
list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number) ? x : y);
How do I alter that code to support what I need to do?
I know I could use binarysearch... I don't want to use that, I want to use linq if possible.
var numbers = new List<int> { 2, 5, 7, 10 };
var seven = numbers.Where(n => n <= 9).Max();
If you have to consider cases where the list will not any number closest, the code would look like,
private static int? GetClosest(List<int> numbers, int number)
{
var shorterEnumerable = numbers.Where(x => x <= number);
var shorterArray = shorterEnumerable as int[] ?? shorterEnumerable.ToArray();
if (shorterArray.Length > 1)
return shorterArray.Max();
return null;
}
even #danielnixon answer is good, this uses agregate
int? closerLow = (int?) list.Aggregate((x,y) => Math.Abs(x-number) < Math.Abs(y-number)
? (x > number ? y : x )
: (y > number ? x : y));
if (closerLow > number) closerLow = null;
I have another problem converting an array from php to c#.
public $array = array(103 => array('', ''), 102 => array('', ''), 101 => array('', '', ''), 100 => array('', '', '', ''));
This is what I have:
public Dictionary<int, List<string>> waddlesById = new Dictionary<int, List<string>>();
problem is whenever I do this:
sizeof($this->array[$waddleId]) - 1
That equals -1, but when do it in c#:
waddlesById[waddleId].Count - 1
equals 0.
This is my construct function:
string maxSeats = String.Empty;
foreach (int waddleId in sledRacing)
{
switch (waddleId)
{
case 103:
case 102:
maxSeats = ",";
break;
case 101:
maxSeats = ",,";
break;
case 100:
maxSeats = ",,,";
break;
}
if (waddlesById.ContainsKey(waddleId))
{
waddlesById[waddleId].Add(maxSeats);
}
else
{
List<string> newInner = new List<string>();
newInner.Add(maxSeats);
waddlesById.Add(waddleId, newInner);
}
}
Any help is appreciated
Using .Count will automatically create the entry. Use waddlesById.ContainsKey(waddleId) instead: http://msdn.microsoft.com/en-us/library/htszx2dy.aspx
I think you are confusing Lists and Arrays in C#. #Simon Witehead is right, you probably need to rethink your code in C# idioms. At the same time it reminded me the LookUp type (which I believe not that commonly known) and I though I'd try to answer you question in (hopefully) somewhat useful way.
Before that, let me clear one thing first: I assume you are trying to create an array with this code:
maxSeats = ",,,";
If that's correct, then here is how you create an array with three elements:
var myArray = new string[3];
// or similar to your PHP code
var myArray = new string[] { "", "", "" };
As for the LookUp example, I think, it provides a more C# idiomatic way of doing this kind of task:
var sledRacing = new[] { 100, 102, 103, 100, 100, 102, 101 };
var lu = sledRacing.ToLookup(
k => k,
k => k == 100 ? new string[3] : (k == 101 ? new string[2] : new string[1])
);
foreach (var g in lu)
{
Console.WriteLine(g.Key);
foreach (var i in g)
{
Console.WriteLine(" - " + i.Length);
}
}
This will produce the following output:
100
- 3
- 3
- 3
102
- 1
- 1
103
- 1
101
- 2
Having said all that (and not knowing much about PHP, so I can't tell if the language lack dynamically sized array or lists and compare), you might need to rethink your code: If you want to use a List then you don't need to size it to start with. Then you might want to be more 'Object oriented' and encapsulate 'Racing Waddle' in a class and use the dictionary (or LookUp) to index them by their id and so on.
There is a similar example on MSDN using LookUp type, that might help too.
Well,
int a = 20;
int b = 30;
int c = 40;
int d = 50;
if (a > b,c,d)
how would i approach this, i have no idea i fail at every turn, its been hours
If there is a short quantity of numbers, you can simply use the boolean logic:
if (a > b && a > c && a > d)
{
}
If you don't know in advance the quantity of numbers, what about creating a collection and compare the first number to the numbers from the collection through a loop?
var numbers = { 30, 40, 50 };
if (!numbers.Any(c => 20 <= c))
{
}
You can put them in an array:
int a = 20;
int[] others = { 30, 40, 50 };
if(others.All(o => a > o))
{
// do something
}
Put them all in a list and do this:
if(list.All(x=> a > x))
Or in one line:
if(new List<int>{a, b, c, d}.All(x=> a > x))
EDIT
I changed the Max() to All(x => a > x) because the a > x will not return a true when a == x whereas Max() will do that.
Non-LINQ example:
if (Math.Max(a, Math.Max(b, Math.Max(c, d))) == a)
{
}
If all you want to know is if the number x is greater than the other numbers, you could either compare them explicitly like if(x>b & b>c) or use something like if(list.All(x=> a > x))
as mentioned above. If you have many numbers and all you want is the higher number, you could sort the list using a quick sort that could be efficient and get the first item.
It's a bit different if you need to compare them and get different comparissons then probably the easiest thing is to loop through the list.