'MAX and MIN on string array in c#
I have started to learn Linq recently. I came across a few inbuild methods like Min() and Max(). The working of these two methods is fine with int[]. But when it comes to string[], I am curious how it will work. I have tried some codes
string[] cars = { "Volvo", "BMW", "Ford", "Mazda" };
Console.WriteLine(cars.Max());
Console.WriteLine(cars.Min());
The output was like this:
**Volvo for Max()
BMW for Min()**
Can you please explain how it is working, is it taking the first letter in alphabetical order or is there any mechanism it is using like based on ASCII values etc?
Solution 1:[1]
All types that implement the IComparable or IComparable interface can be compared, using the CompareTo method implemented by each type. All primitive types implement IComparable<T>
, including char
and string
. LINQ's Min(IEnumerable)
and Max(IEnumerable)
use this implementation to find the minimum or maximum in an enumerable.
String Comparisons
Comparing strings though is a bit more interesting than comparing integers. The strings are typically compared in dictionary order (lexicographically) but ... whose dictionary? Different languages have different sorting rules, and sometimes two letters are considered a single one. Even Danes forget that AA
is equivalent to Å
in Danish.
The dictionary used to compare strings is provided by the CultureInfo class. By default, the current thread's culture is used which typically matches the culture of the end user (in desktop applications) or the system locale in server applications. In a Danish culture for example, AA
is treated differently from aa
- I think one of them is ordered after other letters of the same case and the other isn't, but don't ask me which.
The InvariantCulture specifies a locale-insensitive culture that can be used to handle strings the same way in every locale. It uses mostly sensible settings (eg .
for the decimal point) except dates, where it uses the US format instead of the ISO8601 (YYYY-MM-DD) format as everyone would expect.
Custom comparisons
It's possible to specify a different comparison method by passing a class that implements IComparer
to any LINQ methods affected by order. Min(IEnumerable,IComparer) is one example.
The StringComparer class contains some predefined comparers :
- CurrentCulture is the default
- CurrentCultureIgnoreCase uses the current culture but ignores case, so
A
is equal toa
. This is very useful eg in dictionaries. - InvariantCulture and
InvariantCultureIgnoreCase
use the Invariant culture for ordering - Finally, Ordinal and
OrdinalIgnoreCase
don't use a dictionary but compare the Unicode values of the characters. That's the fastest option if you don't care about locale rules
Solution 2:[2]
.Max()
use Compare(String, String)
which compares two specified String objects and returns an integer that indicates their relative position in the sort order.
Source code of .Max()
for string compare
public static TSource Max<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
Comparer<TSource> comparer = Comparer<TSource>.Default;
TSource value = default(TSource);
if (value == null) {
foreach (TSource x in source) {
if (x != null && (value == null || comparer.Compare(x, value) > 0))
value = x;
}
return value;
}
else {
bool hasValue = false;
foreach (TSource x in source) {
if (hasValue) {
if (comparer.Compare(x, value) > 0) //Compare strings
value = x;
}
else {
value = x;
hasValue = true;
}
}
if (hasValue) return value;
throw Error.NoElements();
}
}
Compare(String, String) https://docs.microsoft.com/en-us/dotnet/api/system.string.compare?view=net-6.0#system-string-compare(system-string-system-string)
Solution 3:[3]
Strings are compared alphabetically, which translates into the following logic:
- which item has a higher first character
- which item has a higher second character
- which item has a higher third character
- ...
The difference is detected at the first character that differs. So, when you compare string1
with string2
, then string1
is greater than string2
if at their first differing character (from left to right), string1
has a greater value at that position than string2
. If string2
is string1
+ string3
, then the first difference between string1
and string2
is beyond the end of string1
and at that point the comparison yields that string2
is greater than string1
.
If you are dissatisfied with this comparison, then you can specify what comparer you intend to use, see here: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.max?view=net-6.0#system-linq-enumerable-max-1(system-collections-generic-ienumerable((-0))-system-collections-generic-icomparer((-0)))
Basically in that case you need to implement an IComparer
and pass it as a second parameter, like
cars.Max(c => c, yourcomparer)
Solution 4:[4]
With string list Min() or Max() follows the first and last word or letter respectively but in case of integers Min() or Max() follows the exact phenomena of finding the Minimum and Maximum numbers from the list. Please check this image and it's output
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Panagiotis Kanavos |
Solution 2 | |
Solution 3 | Lajos Arpad |
Solution 4 |