Il problema da risolvere era il seguente:
Dato un array di N numeri interi, array, con N - 1 numeri dispari e 1 numero pari, si chiede di implementare la funzione:
public static int FindEvenValue(int[] array)
che ritorni il numero pari contenuto nell'array. NON si ammettono istruzioni di selezione, istruzioni di iterazione oppure dell'operatore condizionale "?". Si presuppone che i parametri siano validi e che l'implementazione non richieda una verifica di questi.
Comincio col proporre la mia soluzione e poi elencherò quelle dei partecipanti (in ordine di arrivo).
La mia soluzione si basa sul principio che per conoscere il numero pari bisogna prima di tutto conoscere la sua posizione nell'array. Per determinare l'indice abbiamo due possibilità: o lo cerchiamo nell'array esistente (la soluzione più ovvia se potessimo fare un ciclo) oppure modifichiamo l'array in modo che il numero pari venga spostato in una posizione che conosciamo, ben definita, per esempio la posizione 0. Una modifica, senza usare istruzioni di iterazione o di selezione, è la chiamata del metodo statico Array.Sort, che nella sua versione classica dispone i valori dell'array in ordine crescente, dal più piccolo al più grande.
Tuttavia, questo ordinamento non ci è molto di aiuto perché il numero pari continuerebbe a nascondersi fra quelli dispari e la sua posizione resterebbe un'incognita. Però, se osserviamo con più attenzione, Array.Sort ha una dichiarazione in cui accetta un IComparer, la guida per effettuare l'ordinamento, un'interfaccia che possiamo implementare secondo le nostre esigenze per dire al framework che due oggetti non rispettano le solite regole e si susseguono secondo una logica probabilmente nuova. Siccome abbiamo solo un numero pari, possiamo ordinare l'array in modo che i numeri pari risultino più piccoli di quelli dispari, così il nostro risultato finirà magicamente nella posizione 0.
La classe che ho implementato per questo scopo si chiama OddEvenComparer, con il metodo Compare che restituisce -1 se x < y, 0 se x = y e 1 se x > y:
public class OddEvenComparer: IComparer {
public int Compare(object x, object y) {
int a = Convert.ToInt32(x);
int b = Convert.ToInt32(y);
return Math.Abs(a) % 2 - Math.Abs(b) % 2;
}
}
Richiamare Math.Abs sugli interi diventa fondamentale per gestire i numeri negativi, che altrimenti rischierebbero di far impazzire :-) la funzione.
L'implementazione del metodo FindEvenValue è banale:
public static int FindEvenValue(int[] array) {
Array.Sort(array, new OddEvenComparer());
return array[0];
}
Questa è la mia soluzione, ma qui sotto ne troverete anche di più belle :-)
// Luca Mauri (1)
public static int FindEvenValue(int[] array) {
int eval = 0;
try {
ArrayList list = new ArrayList(array);
eval = (int)list[0];
eval = 1 / (eval % 2);
list.RemoveAt(0);
return FindEvalValue((int[])list.ToArray(typeof(int)));
}
catch {
return eval;
}
}
Matteo Flora (2) ha pensato la mia stessa soluzione.
// Massimo Prota (3)
public static int FindEvenValue(int[] array) {
BitArray ba = new BitArray(array);
ArrayList al = ArrayList.Repeat(0x1, array.Length);
BitArray mask = new BitArray((int[])al.ToArray(typeof(int)));
ba.And(mask);
int[] result = new int[array.Length];
ba.CopyTo(result, 0);
return array[Array.IndexOf(result, 0)];
}
// Andrea Cavallari (4)
public static int FindEvenValue(int[] array) {
int tot = (1 + (array.Length - (array.Length % 2))) * ((array.Length + (array.Length % 2)) / 2);
return array[tot - Ricorsion(array, 0) - 1];
}
private static int Ricorsion(int[] array, int index) {
try {
return ((index + 1) * (Math.Abs(array[index]) % 2)) + Ricorsion(array, index + 1);
}
catch {
return 0;
}
}
// Cristiano Muzi (5)
public class MyObj {
public int Value = 0;
public override bool Equals(object obj) {
int remainder;
Math.DivRem((int)obj, 2, out remainder);
remainder = Math.Abs(remainder);
Value -= (int)obj * (remainder - 1);
return false;
}
public override int GetHashCode() {
return 0;
}
}
public static int FindEvenValue(int[] array) {
MyObj myObj = new MyObj();
Array.IndexOf(array, myObj);
return myObj.Value;
}
// Adrian Florea (6)
public static int FindEvenValue(int[] array) {
XmlSerializer xs = new XmlSerializer(typeof(int[]));
MemoryStream ms = new MemoryStream();
XmlDocument xd = new XmlDocument();
xs.Serialize(ms, array);
ms.Position = 0;
xd.Load(ms);
ms.Close();
return Convert.ToInt32(
xd.SelectSingleNode("ArrayOfInt/int[node() = node() * ((node() * node() + 1) mod 2)]"
).InnerText);
}
Ad Adrian il riconoscimento per la soluzione più originale :-)
Grazie e complimenti a tutti.
flavio.polesello(@)adriacom(.)it