Есть ли способ использовать цикл foreach
для итерации по коллекции назад или в полностью случайном порядке?
Можете ли вы перечислить коллекцию в С# не по порядку?
Ответ 1
Как упоминаются другие ответы, Reverse()
метод расширения позволит вам перечислить последовательность в обратном порядке.
Здесь случайный метод расширения перечисления:
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);
}
}
Ваше использование будет:
foreach (int n in Enumerable.Range(1, 10).OrderRandomly())
Console.WriteLine(n);
Ответ 2
Используя System.Linq
, вы можете сделать...
// List<...> list;
foreach (var i in list.Reverse())
{
}
Для случайного порядка вам придется сортировать его случайным образом, используя list.OrderBy
(другое расширение Linq), а затем повторите этот упорядоченный список.
var rnd = new Random();
var randomlyOrdered = list.OrderBy(i => rnd.Next());
foreach (var i in randomlyOrdered)
{
}
Ответ 3
Я не думаю, что есть способ сделать это напрямую, но в значительной степени as good
использовать метод расширения, который возвращает новую коллекцию с помощью ключевого слова yield return
. Они могут быть получены из ранее существовавшей библиотеки; другие указали, что LINQ имеет метод Reverse
, и такие вещи, как OrderBy
, также будут работать.
Пример: если вы используете метод расширения LINQ Reverse()
на IEnumerable<T>
, который использует yield return
, чтобы предоставить коллекцию в обратном порядке, то выполнение foreach(var myThing in myCollection.Reverse())
будет перечислять коллекцию в обратном порядке.
Важно: ключ yield return
. Это означает "когда я перечисляю эту коллекцию, а затем отправляю вещи". В отличие от альтернативы просто построить новую, обратную коллекцию, которая крайне неэффективна и, возможно, имеет побочные эффекты.
Ответ 4
С С# 2.0 у вас есть возможность использовать ключевое слово yield для реализации пользовательских итераторов очень просто. Вы можете больше узнать о ключевом слове yield в MSDN http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx
Вы можете думать о доходности как о способности вернуть значение из цикла, но вы должны сослаться на приведенную выше ссылку для полного объяснения того, что они представляют и что они могут делать.
Я написал короткий пример того, как реализовать пару пользовательских итераторов. Я реализовал их как методы расширения (http://msdn.microsoft.com/en-us/library/bb383977.aspx), чтобы сделать код немного более поточным, и я также использую инициализаторы массивов (http://msdn.microsoft.com/en-us/library/aa664573.aspx), чтобы установить начальные значения для списка целых чисел.
Для реализации пользовательских итераторов не требуются ни методы расширения, ни инициализаторы массивов, но они являются хорошими функциями С# 3.0, которые помогают писать более чистый код
Вот мои примеры. Он показывает, как перебирать список целых чисел, возвращая только нечетные числа, четные числа, числа в обратном или в случайном порядке.
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];
}
}
}
}
}
Ответ 5
Мне действительно понравился подход cfeduke с LINQ, и это меня испугало, что это сошло с ума. Чтобы добавить к моему предыдущему примеру. Если вы хотите выполнить итерации Odd и Even с помощью LINQ, вы можете использовать
// 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);
}
Ответ 6
Используя IList<T>
из C6 Generic Collection Library, обратная итерация - это функция, а не расширение:
foreach (var i in list.Reverse())
{
}
Кроме того, вы можете использовать метод Shuffle()
для получения произвольного порядка:
var listClone = (IList<T>) list.Clone();
listClone.Shuffle();
foreach (var i in listClone)
{
}
Ответ 7
вы можете сделать это назад:
for (int i=col.count-1; i>0; i--){
DoSomething ( col.item[i]) ;
}
Не уверен в точном синтаксисе, но в том, что парадигма.
Что касается полностью случайного порядка, вы можете получить доступ к элементу коллекции через его индекс. Чтобы убедиться, что вы нажимаете на каждый элемент, вам нужно будет отслеживать, какие элементы вы уже обработали (возможно, скопировав коллекцию, а затем удалив элемент после доступа).
EDIT: более подробная информация о случайном доступе Код для случайного доступа может выглядеть примерно так:
collection c = originalCollection;
while (c.count > 0) {
int i = randomNumber(seed) mod c.count
element d = c[i];
c.remove(d);
DoSomething(d);
}
Ответ 8
Вы можете отсортировать список, предоставив свой собственный Компаратор и перейдя по нему.
Ответ 9
Вы хотите ранжировать коллекцию и взаимодействовать с ней?
Если да, попробуйте следующее:
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>;
Ответ 10
Из моего чтения спецификации языка С#, инструкция foreach iseration зависит от интерфейса struct/class/, который выполняется с использованием функции GetEnumerator(), определенной на ней. Объект, возвращаемый GetEnumerator(), должен иметь MoveNext(), определенный как функция-член. MoveNext() определяется как доступ к "первому" объекту в списке при его первом вызове, а затем "следующий" при последующих вызовах, возвращающий true, пока в списке не будет никаких дополнительных элементов, после чего он вернет false.
Функция Domenic ссылается на return return, сначала появляется в версии 2.0 спецификации, и, по-видимому, она полезна для этой цели. Для версии 1.1 единственным вариантом будет вывод нового интерфейса struct/class/interface из вашей базы и переопределение GetEnumerator() для возврата нового IEnumerator, где функция MoveNext() будет следовать различным правилам в выборе первого элемента коллекции и любого последующий элемент коллекции.
Моя собственная рекомендация заключалась бы в использовании индексированной коллекции, а затем в цикле for с соответствующим вычислением индекса (здесь можно было бы использовать генератор случайных чисел, если необходимо, с целым массивом или другим методом для проверки того, что тот же индекс значение не используется дважды), если вам нужно сделать это на практике.
Ответ 11
Использовать случайное упорядочение
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();