60 votes

Débarrassez-vous des vilaines instructions if

J'ai ce code affreux :

if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2;
if ( v > 145 ) size = 1;
return size;

Comment puis-je me débarrasser des multiples instructions if ?

4 votes

Tu voulais vraiment que les numéros 5 et 6 soient dans cet ordre ?

1 votes

Non, je ne l'ai pas fait, mon erreur.

62 votes

Pour info, je ne pense pas que ce soit particulièrement laid. Il est facile de voir ce qui se passe, il est trivial d'ajouter d'autres cas, c'est clair. La seule chose que j'envisagerais de faire est d'ajouter une liste où les conditions/valeurs sont stockées, mais à part ça, je n'ai aucun problème avec ça.

160voto

mfloryan Points 5544

Que diriez-vous d'une telle approche :

int getSize(int v) {
    int[] thresholds = {145, 117, 68, 51, 22, 10};

    for (int i = 0; i < thresholds.length; i++) {
        if (v > thresholds[i]) return i+1;
    }
    return 1;
}

Fonctionnellement : (Démontré en Scala)

def getSize(v: Int): Int = {
  val thresholds = Vector(145, 117, 68, 51, 22, 10)
  thresholds.zipWithIndex.find(v > _._1).map(_._2).getOrElse(0) + 1
}

10 votes

L'avantage de cette approche est qu'elle peut être facilement étendue à d'autres étapes ou à une gamme plus large sans grand effort.

1 votes

+1 c'est la solution non orientée objet la plus élégante ici :-)

2 votes

Il manque une dernière déclaration de retour, cela ne compile pas (en java)

88voto

barjak Points 4682

Utilisation de la NavigableMap API :

NavigableMap<Integer, Integer> s = new TreeMap<Integer, Integer>();
s.put(10, 6);
s.put(22, 5);
s.put(51, 4);
s.put(68, 3);
s.put(117, 2);
s.put(145, 1);

return s.lowerEntry(v).getValue();

2 votes

Si vous laissez les clés comme l'a fait le PO, vous pouvez utiliser lowerEntry au lieu de floorEntry. De cette façon, les données sont cohérentes avec l'OP.

5 votes

Très bonne solution (+1), en fait je dirais que c'est la seule solution non moche ici.

11 votes

Eh bien, très peu laid jusqu'à ce que vous regardiez les frais généraux.

82voto

Le problème le plus évident avec la solution du PO est la ramification, je suggérerais donc une régression polynomiale. Cela donnera une belle expression sans branchements de la forme

size = round(k_0 + k_1 * v + k_2 * v^2 + ...)

Bien sûr, vous n'obtiendrez pas un résultat exact, mais si vous pouvez tolérer une certaine déviance, c'est une alternative très performante. Puisque le comportement "non modifié" de la fonction originale pour les valeurs où v<10 est impossible à modéliser avec un polynôme, j'ai pris la liberté de supposer une interpolation de retenue d'ordre zéro pour cette région.

Pour un polynôme de 45 degrés avec les coefficients suivants,

-9.1504e-91 1.1986e-87 -5.8366e-85 1.1130e-82 -2.8724e-81 3.3401e-78 -3.3185e-75  9.4624e-73 -1.1591e-70 4.1474e-69 3.7433e-67 2.2460e-65 -6.2386e-62 2.9843e-59 -7.7533e-57 7.7714e-55 1.1791e-52 -2.2370e-50 -4.7642e-48 3.3892e-46 3.8656e-43 -6.0030e-41 9.4243e-41 -1.9050e-36 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23  6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23 6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 3.6100e-01 -6.2117e-01 6.3657e+00

vous obtenez une courbe magnifiquement ajustée :

alt text

Et comme vous pouvez le voir, vous obtenez une erreur à la norme 1 de seulement 1,73 sur toute la gamme de 0 à 200* !

*Résultats pour v[0,200] peut varier.

0 votes

J'adore cela car j'ai toujours aimé trouver des expressions qui "emballent" les données d'une recherche dans des expressions mathématiques. Prenez quelques constantes, ajoutez quelques multiplications, additions, modulus, abs(), floor(), etc., et vous pouvez faire des choses amusantes pour calculer des choses comme le nombre de jours de chaque mois. Mais je n'ai jamais pensé à un polynôme pour ce genre de choses !

2 votes

Wow ! Pourriez-vous nous en dire plus sur les outils que vous avez utilisés pour produire ce résultat ?

0 votes

Comment as-tu trouvé les coefficients ? Est-ce que c'est des maths avancées ?

75voto

Jigar Joshi Points 116533
if ( v > 145 ) size = 1;
else if ( v > 117 ) size = 2;
else if ( v > 68 ) size = 3;
else if ( v > 51 ) size = 4;
else if ( v > 22 ) size = 5;
else if ( v > 10 ) size = 6;

return size;     

C'est mieux pour votre cas.

En option, vous devriez choisir le Switch Case dans la mesure du possible.

Update: Si vous avez analysé que la valeur de 'v' se situe généralement dans une plage inférieure (<10) dans la plupart des cas, vous pouvez ajouter ceci.

if(v < 10)           size = SOME_DEFAULT_VALUE;
else if ( v > 145 )  size = 1;
else if ( v > 117 )  size = 2;
else if ( v > 68 )   size = 3;
else if ( v > 51 )   size = 4;
else if ( v > 22 )   size = 5;
else if ( v > 10 )   size = 6;   

further : Vous pouvez également modifier la séquence des conditions, en fonction de votre analyse. Si vous savez que la plupart des valeurs sont inférieures à 10 et qu'en second lieu, la plupart des valeurs se situent entre 68 et 117, vous pouvez modifier la séquence de conditions en conséquence.

Edits :

if(v < 10)           return SOME_DEFAULT_VALUE;
else if ( v > 145 )  return 1;
else if ( v > 117 )  return 2;
else if ( v > 68 )   return 3;
else if ( v > 51 )   return 4;
else if ( v > 22 )   return 5;
else if ( v > 10 )   return 6;

0 votes

"En option, vous devriez choisir le Switch Case dans la mesure du possible" pourquoi ?

0 votes

@NimChimpsky Ce serait plus readable . Je ne dis pas qu'il est meilleur en termes de performances, cela dépend de nombreux facteurs.

93 votes

Encore mieux : il suffit de renvoyer la valeur tout de suite sans utiliser les intermédiaires. size variable.

51voto

dhblah Points 2337
return v > 145 ? 1 
     : v > 117 ? 2 
     : v > 68 ? 3 
     : v > 51 ? 4 
     : v > 22 ? 5 
     : v > 10 ? 6 
     : "put inital size value here";

0 votes

Vous êtes sérieux ? C'est beaucoup plus illisible, et ce n'est pas facile à changer si les règles de "taille" changent.

13 votes

Pourriez-vous lire la question initiale ? "Comment puis-je me débarrasser des multiples instructions if ?" Comme vous pouvez le constater, il n'y a pas d'instructions "if" dans ma réponse.

12 votes

@gasan, bien sûr, vous avez supprimé le if's mais l'opérateur a affirmé que son code était ugly et destiné à le rendre plus lisible... vous croyez vraiment que c'est... plus joli ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X