Pergunta

Existe uma maneira de usar um loop foreach para percorrer uma coleção para trás ou em uma ordem completamente aleatória?

Foi útil?

Solução

Como outras respostas mencionar, a Reverse() método de extensão vai deixar você enumerar uma sequência na ordem inversa.

Aqui está um método de extensão enumeração aleatória:

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);
    }
}

O seu uso seria:

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

Outras dicas

Usando System.Linq você poderia fazer ...

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

Para uma ordem aleatória você teria que classificá-lo aleatoriamente usando list.OrderBy (outra extensão Linq) e depois iterate que lista ordenada.

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

Eu não acho que há uma maneira de fazê-lo diretamente, mas é praticamente as good usar um método de extensão que retorna uma nova coleção através da palavra-chave yield return. Estes poderiam vir de uma pré -existente biblioteca; os outros têm apontado que LINQ tem um método Reverse, e coisas como OrderBy também funcionaria.

Exemplo:. Se você usar o Reverse() LINQ método de extensão em IEnumerable<T>, que usa yield return para dar a coleção em ordem inversa, em seguida, fazendo um foreach(var myThing in myCollection.Reverse()) irá enumerar através da coleção em ordem inversa

Importante : yield return é fundamental. Significa "quando eu enumerar essa coleção, em seguida, ir buscar as coisas." Em oposição à alternativa de simplesmente construir um new , coleção invertida, que é altamente ineficiente e possivelmente tem efeitos colaterais.

Eu realmente gostei abordagem cfeduke com LINQ e ele me incomoda que ela escorregou minha mente. Para adicionar ao meu exemplo anterior. Se você quer fazer as iterações pares e ímpares com a ajuda de LINQ você pode usar

// 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);
}

A partir de C # 2.0 tem a capacidade de usar a palavra-chave yield para implementar iteradores personalizados realmente fácil. Você pode ler mais sobre o rendimento palavra-chave em cima da MSDN http://msdn.microsoft .com / en-us / library / 9k7k7cf0.aspx

Você pode pensar em um rendimento como a capacidade de retornar um valor de dentro de um loop, mas você deve consultar o link acima para uma explicação completa sobre o que são eo que eles podem fazer.

Eu escrevi um pequeno exemplo de como implementar um par de iteradores personalizados. Eu tenho implementado-los como métodos de extensão ( http://msdn.microsoft.com /en-us/library/bb383977.aspx ) para tornar o código um pouco mais córrego alinhados e eu também usam inicializadores de matriz ( http://msdn.microsoft.com/en-us/library/aa664573.aspx ) para definir os valores iniciais para a lista de números inteiros.

Nem os métodos de extensão nem initializers matriz são necessários para a aplicação iterators personalizados, mas eles são agradáveis ??características do c # 3.0 que ajuda a escrever código mais limpo

Aqui estão os meus exemplos. Ele mostra como iterar sobre uma lista de inteiros por retornando apenas números ímpares, números pares, os números invertidos ou de forma completamente aleatória.

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];
                }
            }
        }
    }
}

Você pode ordenar a lista por fornecer seu próprio comparador e iterar sobre isso.

Você pode fazê-lo para trás:

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

Não certo sobre a sintaxe exata, mas isso é o paradigma.

Quanto à ordem completamente aleatória, você pode acessar um elemento de coleção via-lo do índice. Para garantir que você acertar todos os item, você precisa manter o controle de quais elementos você já tinha processado (provavelmente copiando a coleta e, em seguida, remover o elemento após o acesso).

EDIT: Mais detalhes de acesso aleatório O código para o acesso aleatório poderia ser algo como isto:

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

Você quer rand uma coleção e interagir com ele?

Se sim, tente o seguinte:

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>;

De minha leitura do # Language Specification C, a declaração foreach iteração depende da struct / classe / interface de que está sendo iterado tendo a função GetEnumerator () definido em cima dele. O objecto devolvido por GetEnumerator () deve ter moveNext () definida como uma função de membro. MoveNext () é definida como o acesso ao "primeiro" objeto na lista em sua primeira chamada, em seguida, o "próximo" em chamadas subseqüentes, retornando true até que não existem mais elementos na lista, na qual ela retorna false.

A característica Domenic refere-se, rendimento de retorno, aparece pela primeira vez a versão 2.0 da especificação, e não parece ser útil para este fim. Para a versão 1.1, a sua única opção seria a de obter um struct new / classe / interface da sua base e substituir GetEnumerator () para retornar uma nova IEnumerator, onde a função MoveNext () iria seguir regras diferentes em selecionar o primeiro elemento de coleção e qualquer subseqüente elemento de coleção.

A minha recomendação seria usar uma coleção indexada, em seguida, usar um loop com um cálculo do índice apropriado (aqui pode-se usar um gerador de números aleatórios, se necessário, com uma matriz de inteiros ou alguma outra técnica para verificar se o mesmo índice valor não é usado duas vezes) se você tiver que fazer isso na prática.

Use aleatória ordenação
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();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top