I have started to learn Linq recently. I came across few inbuild methods like Min() and Max(). The working of these two methods are 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:
**Volvo for Max()
BMW for Min()**
Can you some 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.
CodePudding user response:
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
CodePudding user response:
.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)
CodePudding user response:
With string list Min() and Max() follows the first and last word or letter respectively but in case of integers Min() and Max() follows the exact phenomena of finding the Minimum and Maximum numbers from the list. enter image description here
CodePudding user response:
The source code of .Max()
:
public static TSource Max<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
Comparer<TSource> @default = Comparer<TSource>.Default;
TSource val = default(TSource);
if (val == null)
{
foreach (TSource item in source)
{
if (item != null && (val == null || @default.Compare(item, val) > 0))
{
val = item;
}
}
return val;
}
bool flag = false;
foreach (TSource item2 in source)
{
if (flag)
{
if (@default.Compare(item2, val) > 0)
{
val = item2;
}
}
else
{
val = item2;
flag = true;
}
}
if (flag)
{
return val;
}
throw Error.NoElements();
}
The source code of .Min()
:
public static TSource Min<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
Comparer<TSource> @default = Comparer<TSource>.Default;
TSource val = default(TSource);
if (val == null)
{
foreach (TSource item in source)
{
if (item != null && (val == null || @default.Compare(item, val) < 0))
{
val = item;
}
}
return val;
}
bool flag = false;
foreach (TSource item2 in source)
{
if (flag)
{
if (@default.Compare(item2, val) < 0)
{
val = item2;
}
}
else
{
val = item2;
flag = true;
}
}
if (flag)
{
return val;
}
throw Error.NoElements();
}