Question

Existe-t-il un moyen d'utiliser une foreach boucle pour parcourir une collection en arrière ou dans un ordre complètement aléatoire?

Était-ce utile?

La solution

Comme d'autres réponses le mentionnent, la Reverse() méthode d'extension sera vous permet d'énumérer une séquence dans l'ordre inverse.

Voici une méthode d'extension d'énumération aléatoire:

public static IEnumerable<T> OrderRandomly<T>(this IEnumerable<T> sequence)
{
    Random random = new Random();
    List<T> copy = sequence.ToList();

    while (copy.Count > 0)
    {
        int index = random.Next(copy.Count);
        yield return copy[index];
        copy.RemoveAt(index);
    }
}

Votre utilisation serait:

foreach (int n in Enumerable.Range(1, 10).OrderRandomly())
    Console.WriteLine(n);

Autres conseils

En utilisant System.Linq vous pourriez faire ...

// List<...> list;
foreach (var i in list.Reverse())
{
}

Pour un ordre aléatoire, vous devez le trier de manière aléatoire à l'aide de list.OrderBy (une autre extension Linq), puis itérer cette liste ordonnée.

var rnd = new Random();
var randomlyOrdered = list.OrderBy(i => rnd.Next());
foreach (var i in randomlyOrdered)
{
}

Je ne pense pas qu'il soit possible de le faire directement, mais il est plutôt as good d'utiliser une méthode d'extension qui renvoie une nouvelle collection via le mot clé yield return. Ces éléments pourraient proviennent d'une bibliothèque préexistante; les autres ont fait remarquer que LINQ utilisait une méthode Reverse et que des choses comme OrderBy fonctionneraient également.

Exemple: si vous utilisez la méthode d’extension LINQ Reverse() sur IEnumerable<T>, qui utilise foreach(var myThing in myCollection.Reverse()) pour donner la collection dans l’ordre inverse, effectuer une <=> énumère la collection dans l’ordre inverse.

Important : <=> est la clé. Cela signifie & «Quand je vais énumérer cette collection, puis aller chercher des objets. &»; Contrairement à l’alternative consistant à créer simplement une nouvelle collection, qui est très inefficace et peut avoir des effets secondaires.

En fait, j’ai aimé l’approche de cfeduke avec LINQ et ça m’ennuie que cela m’a échappé. Pour ajouter à mon exemple précédent. Si vous voulez faire les itérations Odd et Even à l’aide de LINQ, vous pouvez utiliser

// Even
foreach (var i in ints.FindAll(number => number % 2 == 0))
{
      Console.WriteLine(i);
}

// Odd
foreach (var i in ints.FindAll(number => number % 2 != 0))
{
      Console.WriteLine(i);
}

À l'aide d'une IList<T> de la bibliothèque de collections génériques C5 , l'itération inversée est une fonctionnalité. , plutôt que l'extension:

foreach (var i in list.Reverse())
{
}

De même, vous pouvez utiliser la méthode Shuffle() pour obtenir un ordre aléatoire:

var listClone = (IList<T>) list.Clone();
listClone.Shuffle();
foreach (var i in listClone)
{
}

À partir de C # 2.0, vous pouvez utiliser le mot-clé de rendement pour implémenter des itérateurs personnalisés très facilement. Vous pouvez en savoir plus sur le mot-clé rendement à l'adresse MSDN http://msdn.microsoft .com / fr-us / library / 9k7k7cf0.aspx

Vous pouvez penser à un rendement comme à la possibilité de renvoyer une valeur depuis une boucle, mais vous devez vous reporter au lien ci-dessus pour obtenir une explication complète de ce qu’elles sont et de ce qu’elles peuvent faire.

J'ai écrit un court exemple sur la manière d'implémenter quelques itérateurs personnalisés. Je les ai implémentés en tant que méthodes d'extension ( http://msdn.microsoft.com /en-us/library/bb383977.aspx ) pour que le code soit un peu plus ligné et j'utilise également les initialiseurs de tableaux ( http://msdn.microsoft.com/en-us/library/aa664573.aspx ) pour définir les valeurs initiales de la liste des entiers.

Ni les méthodes d'extension ni les initialiseurs de tableaux ne sont nécessaires pour implémenter des itérateurs personnalisés, mais ce sont de jolies fonctionnalités de c # 3.0 qui permet d'écrire du code plus propre

Voici mes exemples. Il montre comment parcourir une liste d’entiers en ne renvoyant que des nombres impairs, des nombres pairs, les nombres inversés ou complètement aléatoires.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> ints = 
                new List<int> { 1,2,3,4,5,6,7,8,9,10};

            Console.WriteLine("Iterating over Odd numbers only.");
            foreach (int i in ints.Odd())
            {
                Console.WriteLine(i);
            }

            Console.WriteLine("Iterating over Even numbers only.");
            foreach (int i in ints.Even())
            {
                Console.WriteLine(i);
            }

            Console.WriteLine("Iterating over the list in reversed order.");
            foreach (int i in ints.Reversed())
            {
                Console.WriteLine(i);
            }

            Console.WriteLine("Iterating over the list in random order.");
            foreach (int i in ints.Random())
            {
                Console.WriteLine(i);
            }

            Console.ReadLine();
        }
    }

    public static class ListExtensions
    {
        /// <summary>
        /// Iterates over the list only returns even numbers
        /// </summary>
        /// <param name="list"></param>
        public static IEnumerable<int> Even(this List<int> list)
        {
            foreach (var i in list)
            {
                if (i % 2 == 0)
                 {
                    yield return i;
                }
           }
        }

        /// <summary>
        /// Iterates over the list only returns odd numbers
        /// </summary>
        public static IEnumerable<int> Odd(this List<int> list)
        {
            foreach (var i in list)
            {
                if (i % 2 != 0)
                {
                    yield return i;
                }
            }
        }

        /// <summary>
        /// Iterates over the list in reversed order
        /// </summary>
        public static IEnumerable<int> Reversed(this List<int> list)
        {
            for (int i = list.Count; i >= 0; i--)
            {
                yield return i;
            }
        }

        /// <summary>
        /// Iterates over the list in random order
        /// </summary>
        public static IEnumerable<int> Random(this List<int> list)
        {
            // Initialize a random number generator with a seed.
            System.Random rnd =
                new Random((int)DateTime.Now.Ticks);

            // Create a list to keep track of which indexes we've
            // already returned
            List<int> visited =
                new List<int>();

            // loop until we've returned the value of all indexes
            // in the list
            while (visited.Count < list.Count)
            {
                int index =
                    rnd.Next(0, list.Count);

                // Make sure we've not returned it already
                if (!visited.Contains(index))
                {
                    visited.Add(index);
                    yield return list[index];
                }
            }
        }
    }
}

Vous pouvez trier la liste en fournissant votre propre comparateur et effectuer une itération sur celui-ci.

vous pouvez le faire à l'envers:

for (int i=col.count-1; i>0; i--){ 
      DoSomething ( col.item[i]) ;
}

Vous n'êtes pas certain de la syntaxe exacte, mais c'est le paradigme.

En ce qui concerne l’ordre totalement aléatoire, vous pouvez accéder à un élément de la collection via son index. Pour vous assurer de toucher chaque élément, vous devez garder en mémoire les éléments que vous avez déjà traités (probablement en copiant la collection puis en supprimant l'élément après l'accès).

EDIT: Plus de détails pour l'accès aléatoire Le code de l'accès aléatoire pourrait ressembler à ceci:

 collection c = originalCollection;
 while (c.count > 0) {
     int i = randomNumber(seed) mod c.count
     element d = c[i];
     c.remove(d);
     DoSomething(d);
}

Voulez-vous explorer une collection et interagir avec elle?

Si oui, essayez ceci:

Random rand = new Random(Environment.TickCount);

test.Sort((string v1, string v2) => {
                if (v1.Equals(v2))
                {
                    return 0;
                }

                int x = rand.Next();
                int y = rand.Next();

                if (x == y)
                {
                    return 0;
                }
                else if (x > y)
                {
                    return 1;
                }

                return -1; 
            });

for (string item in test)
{
  Console.WriteLn(item);
}
// Note that test is List<string>;

D'après ma lecture de la spécification du langage C #, l'instruction d'itération foreach dépend de la structure / classe / interface qui est itérée et sur laquelle la fonction GetEnumerator () est définie. MoveNext () doit être défini en tant que fonction membre pour l'objet renvoyé par GetEnumerator (). MoveNext () est défini comme accédant à la & Quot; première & Quot; objet dans la liste lors de son premier appel, puis le " next " lors des appels suivants, renvoie la valeur true jusqu'à ce qu'il n'y ait plus d'éléments dans la liste, sur lesquels elle renvoie la valeur false.

La fonctionnalité utilisée par Domenic, return return, apparaît pour la première fois dans la version 2.0 de la spécification et semble être utile à cet effet. Pour la version 1.1, votre seule option serait de dériver une nouvelle structure / classe / interface de votre base et de remplacer GetEnumerator () pour renvoyer un nouvel IEnumerator, où la fonction MoveNext () suivrait des règles différentes lors de la sélection du premier élément de la collection élément de collection suivant.

Ma propre recommandation serait d'utiliser une collection indexée, puis d'utiliser une boucle for avec un calcul d'index approprié (ici, on pourrait utiliser un générateur de nombres aléatoires si nécessaire, avec un tableau entier ou une autre technique permettant de vérifier que le même index la valeur n'est pas utilisée deux fois) si vous devez le faire dans la pratique.

Utilisez un ordre aléatoire
http://www.dailycoding.com/..using_linq.aspx

List<Employee> list = new List<Employee>();

list.Add(new Employee { Id = 1, Name = "Davolio Nancy" });
list.Add(new Employee { Id = 2, Name = "Fuller Andrew" });
list.Add(new Employee { Id = 3, Name = "Leverling Janet" });
list.Add(new Employee { Id = 4, Name = "Peacock Margaret" });
list.Add(new Employee { Id = 5, Name = "Buchanan Steven" });
list.Add(new Employee { Id = 6, Name = "Suyama Michael" });
list.Add(new Employee { Id = 7, Name = "King Robert" });
list.Add(new Employee { Id = 8, Name = "Callahan Laura" });
list.Add(new Employee { Id = 9, Name = "Dodsworth Anne" });

list = list.OrderBy(emp => Guid.NewGuid()).ToList();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top