J'ai besoin de reculer dans un tableau, j'ai donc un code comme celui-ci:
for (int i = myArray.Length - 1; i >= 0; i--)
{
// Do something
myArray[i] = 42;
}
Existe-t-il une meilleure façon de le faire?
Mise à jour: j'espérais que C # avait peut-être un mécanisme intégré pour cela, comme:
foreachbackwards (int i in myArray)
{
// so easy
}
Mise à jour 2: il existe de meilleures façons. Rune remporte le prix avec:
for (int i = myArray.Length; i-- > 0; )
{
//do something
}
//or
for (int i = myArray.Length; i --> 0; )
{
// do something
}
ce qui est encore mieux en C normal (grâce à Twotymz):
for (int i = lengthOfArray; i--; )
{
//do something
}
Réponses:
Bien que certes un peu obscur, je dirais que la manière la plus typographiquement la plus agréable de le faire est
la source
En C ++, vous avez fondamentalement le choix entre des itérations à l'aide d'itérateurs ou d'index. Selon que vous disposez d'un tableau simple ou a
std::vector
, vous utilisez différentes techniques.Utilisation de std :: vector
Utiliser des itérateurs
C ++ vous permet de faire cela en utilisant
std::reverse_iterator:
Utilisation d'indices
Le type intégral non signé renvoyé par
std::vector<T>::size
n'est pas toujoursstd::size_t
. Cela peut être supérieur ou inférieur. Ceci est crucial pour que la boucle fonctionne.Cela fonctionne, car les valeurs des types intégraux non signés sont définies au moyen de modulo leur nombre de bits. Ainsi, si vous réglez
-N
, vous vous retrouvez à(2 ^ BIT_SIZE) -N
Utilisation de tableaux
Utiliser des itérateurs
Nous utilisons
std::reverse_iterator
pour faire l'itération.Utilisation d'indices
Nous pouvons utiliser en toute sécurité
std::size_t
ici, par opposition à ci-dessus, carsizeof
renvoie toujoursstd::size_t
par définition.Éviter les pièges avec sizeof appliqué aux pointeurs
En fait, la manière ci-dessus de déterminer la taille d'un tableau est nul. Si a est en fait un pointeur au lieu d'un tableau (ce qui arrive assez souvent, et les débutants le confondront), il échouera silencieusement. Une meilleure façon est d'utiliser ce qui suit, qui échouera au moment de la compilation, si un pointeur est donné:
Cela fonctionne en obtenant d'abord la taille du tableau passé, puis en déclarant de renvoyer une référence à un tableau de type char de la même taille.
char
est défini comme ayantsizeof
de: 1. Ainsi, le tableau retourné aura unsizeof
de: N * 1, ce que nous recherchons, avec seulement une évaluation du temps de compilation et une surcharge d'exécution nulle.Au lieu de faire
Changez votre code pour qu'il le fasse maintenant
la source
end
etbegin
dans l'ordre inverse?En C # , à l'aide de Visual Studio 2005 ou version ultérieure, tapez «forr» et appuyez sur [TAB] [TAB] . Cela s'étendra à une
for
boucle qui va en arrière dans une collection.Il est si facile de se tromper (du moins pour moi), que j'ai pensé que mettre cet extrait de code serait une bonne idée.
Cela dit, j'aime
Array.Reverse()
/Enumerable.Reverse()
puis je répète avant de mieux - ils plus clairement l' intention déclarent.la source
Je préférerais toujours un code clair au code « typographiquement agréable ». Ainsi, j'utiliserais toujours:
Vous pouvez le considérer comme le moyen standard de boucler en arrière.
Juste mes deux cents...
la source
En C # avec Linq :
la source
C'est certainement le meilleur moyen pour tout tableau dont la longueur est un type intégral signé. Pour les tableaux dont les longueurs sont de type intégral non signé (par exemple un
std::vector
en C ++), vous devez modifier légèrement la condition de fin:Si vous venez de dire
i >= 0
, c'est toujours vrai pour un entier non signé, donc la boucle sera une boucle infinie.la source
Cela me semble correct. Si l'indexeur n'était pas signé (uint, etc.), vous devrez peut-être en tenir compte. Appelez-moi paresseux, mais dans ce cas (non signé), je pourrais simplement utiliser une contre-variable:
(en fait, même ici, vous devez faire attention aux cas comme arr.Length = uint.MaxValue ... peut-être a! = quelque part ... bien sûr, c'est un cas très improbable!)
la source
En CI, faites ceci:
Exemple C # ajouté par MusiGenesis:
la source
La meilleure façon de faire cela en C ++ est probablement d'utiliser des adaptateurs d'itérateur (ou mieux, de plage), qui transformeront paresseusement la séquence lorsqu'elle est parcourue.
Fondamentalement,
Affiche la plage "range" (ici, elle est vide, mais je suis assez sûr que vous pouvez ajouter des éléments vous-même) dans l'ordre inverse. Bien sûr, il n'est pas très utile d'itérer simplement la plage, mais passer cette nouvelle plage à des algorithmes et à d'autres choses est plutôt cool.
Ce mécanisme peut également être utilisé pour des utilisations beaucoup plus puissantes:
Calculera paresseusement la plage "plage", où la fonction "f" est appliquée à tous les éléments, les éléments pour lesquels "p" n'est pas vrai sont supprimés, et finalement la plage résultante est inversée.
La syntaxe de pipe est la plus lisible de l'OMI, étant donné son infixe. La mise à jour de la bibliothèque Boost.Range en attente de révision l'implémente, mais il est assez simple de le faire vous-même également. C'est encore plus cool avec un DSEL lambda de générer la fonction f et le prédicat p en ligne.
la source
la source
Je préfère une boucle while. C'est plus clair pour moi que de décrémenter
i
dans la condition d'une boucle forla source
J'utiliserais le code dans la question d'origine, mais si vous vouliez vraiment utiliser foreach et avoir un index entier en C #:
la source
Je vais essayer de répondre à ma propre question ici, mais je n'aime pas vraiment ça non plus:
la source
REMARQUE: Ce message a fini par être beaucoup plus détaillé et donc hors sujet, je m'excuse.
Cela étant dit, mes pairs le lisent et pensent qu'il est utile «quelque part». Ce fil n'est pas l'endroit. J'apprécierais vos commentaires sur où cela devrait aller (je suis nouveau sur le site).
Quoi qu'il en soit, c'est la version C # dans .NET 3.5 qui est incroyable en ce qu'elle fonctionne sur n'importe quel type de collection en utilisant la sémantique définie. Il s'agit d'une mesure par défaut (réutilisation!) Et non de la minimisation des performances ou du cycle du processeur dans la plupart des scénarios de développement courants, bien que cela ne semble jamais être ce qui se passe dans le monde réel (optimisation prématurée).
*** Méthode d'extension travaillant sur n'importe quel type de collection et prenant un délégué d'action attend une valeur unique du type, le tout exécuté sur chaque élément à l'envers **
Requres 3.5:
Anciennes versions de .NET ou souhaitez-vous mieux comprendre les composants internes de Linq? Continuez à lire… Ou pas…
HYPOTHÈSE: Dans le système de type .NET, le type Array hérite de l'interface IEnumerable (et non du IEnumerable générique uniquement IEnumerable).
C'est tout ce dont vous avez besoin pour parcourir du début à la fin, mais vous souhaitez vous déplacer dans la direction opposée. Comme IEnumerable fonctionne sur un tableau de type 'objet', tout type est valide,
MESURE CRITIQUE: Nous supposons que si vous pouvez traiter n'importe quelle séquence dans l'ordre inverse qui est «meilleure», alors ne pouvoir le faire que sur des entiers.
Solution a pour .NET CLR 2.0-3.0:
Description: Nous accepterons toute instance d'implémentation IEnumerable avec le mandat que chaque instance qu'elle contient est du même type. Donc, si nous recevons un tableau, le tableau entier contient des instances de type X. Si d'autres instances sont d'un type! = X, une exception est levée:
Un service singleton:
classe publique ReverserService {private ReverserService () {}
[TestFixture] classe publique Testing123 {
la source