Durante la mia carriera di programmatore ho preso l'abitudine di introdurre una variabile flag che indica che il primo confronto è avvenuto, proprio come fa Msft nella sua implementazione del metodo di estensione linq Max ()
public static int Max(this IEnumerable<int> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
int num = 0;
bool flag = false;
foreach (int num2 in source)
{
if (flag)
{
if (num2 > num)
{
num = num2;
}
}
else
{
num = num2;
flag = true;
}
}
if (!flag)
{
throw Error.NoElements();
}
return num;
}
Tuttavia ultimamente ho incontrato alcuni eretici, che lo implementano iniziando solo dal primo elemento e assegnandolo al risultato, e oh no - si è scoperto che gli autori di STL e Java hanno preferito quest'ultimo metodo.
Java:
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) > 0)
candidate = next;
}
return candidate;
}
STL:
template<class _FwdIt> inline
_FwdIt _Max_element(_FwdIt _First, _FwdIt _Last)
{ // find largest element, using operator<
_FwdIt _Found = _First;
if (_First != _Last)
for (; ++_First != _Last; )
if (_DEBUG_LT(*_Found, *_First))
_Found = _First;
return (_Found);
}
Ci sono delle preferenze tra un metodo o l'altro? Ci sono ragioni storiche per questo? Un metodo è più pericoloso di un altro?
UPDATE : Si noti che la versione java è in grado di generare eccezioni con la riga T candidate = i.next();
ed è possibile ottenere lo stesso comportamento in C # con la clausola di guardia come mostrato nel secondo parte della risposta di @ratchet freak.