ループを使用しforeach
てコレクションを逆方向または完全にランダムな順序で繰り返す方法はありますか?
11 に答える
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)
{
}
他の回答が言及しているように、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);
私は実際にLINQを使用したcfedukeアプローチが好きでしたが、それが私の心を滑らせたことは私を悩ませます。前の例に追加します。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);
}
直接行う方法はないと思いますが、キーワードを介してas good
新しいコレクションを返す拡張メソッドを使用するのがほとんどです。これらは既存のライブラリから取得できます。他の人は、LINQにはメソッドがあり、そのようなものも機能することを指摘しています。yield return
Reverse
OrderBy
例: LINQ 拡張メソッドReverse()
onIEnumerable<T>
を使用yield return
すると、コレクションが逆順で与えられ、a を実行するforeach(var myThing in myCollection.Reverse())
と、コレクションが逆順で列挙されます。
重要:yield return
が鍵です。これは、「このコレクションを列挙したら、取得に行く」という意味です。逆のコレクションを新しく作成するという代替案とは対照的に、これは非常に非効率的であり、副作用がある可能性があります。
C5 Generic Collection LibraryIList<T>
のを使用すると、逆反復は拡張ではなく機能です。
foreach (var i in list.Reverse())
{
}
同様に、Shuffle()
メソッドを使用してランダムな順序を取得できます。
var listClone = (IList<T>) list.Clone();
listClone.Shuffle();
foreach (var i in listClone)
{
}
C# 2.0 では、yield キーワードを使用してカスタム イテレータを非常に簡単に実装できます。yield キーワードの詳細については、MSDN http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspxを参照してください。
yield はループ内から値を返す機能と考えることができますが、yield とは何か、何ができるかについての完全な説明については、上記のリンクを参照してください。
いくつかのカスタム イテレータを実装する方法について、簡単な例を書きました。それらを拡張メソッド ( http://msdn.microsoft.com/en-us/library/bb383977.aspx ) として実装して、コードをもう少し合理化して、配列初期化子 ( http://msdn .microsoft.com/en-us/library/aa664573.aspx ) を使用して、整数のリストの初期値を設定します。
カスタム反復子を実装するために拡張メソッドも配列初期化子も必要ありませんが、これらは c# 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];
}
}
}
}
}
ランダムな順序を使用
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();
あなたはそれを逆にすることができます:
for (int i=col.count-1; i>0; i--){
DoSomething ( col.item[i]) ;
}
正確な構文については定かではありませんが、それがパラダイムです。
完全にランダムな順序については、インデックスを介してコレクション要素にアクセスできます。すべてのアイテムを確実にヒットさせるには、すでに処理した要素を追跡する必要があります (おそらく、コレクションをコピーし、アクセス後に要素を削除することによって)。
編集: ランダム アクセスの詳細 ランダム アクセスのコードは次のようになります。
collection c = originalCollection;
while (c.count > 0) {
int i = randomNumber(seed) mod c.count
element d = c[i];
c.remove(d);
DoSomething(d);
}
独自の Comparator を指定して List をソートし、その Comparator を反復処理できます。
コレクションをランドして、それとやり取りしたいですか?
はいの場合、これを試してください:
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>;
C# 言語仕様を読んだところによると、foreach 反復ステートメントは、GetEnumerator() 関数が定義された反復されている構造体/クラス/インターフェイスに依存しています。GetEnumerator() によって返されるオブジェクトには、MoveNext() がメンバー関数として定義されている必要があります。MoveNext() は、最初の呼び出しでリスト内の「最初の」オブジェクトにアクセスし、その後の呼び出しで「次の」オブジェクトにアクセスするように定義されており、リストにそれ以上の要素が存在しなくなるまで true を返し、それ以上要素が存在しなくなると false を返します。
Domenic が言及している yield return という機能は、仕様の 2.0 バージョンで最初に登場し、この目的に役立つようです。バージョン 1.1 の場合、唯一のオプションは、ベースから新しい構造体/クラス/インターフェイスを派生させ、GetEnumerator() をオーバーライドして新しい IEnumerator を返すことです。ここで、MoveNext() 関数は、最初のコレクション要素を選択する際に異なる規則に従います。後続のコレクション要素。
私自身の推奨事項は、インデックス付きコレクションを使用してから、適切なインデックス計算で for ループを使用することです (ここでは、必要に応じて整数配列または同じインデックス値が存在しないことを確認するための他の手法を使用して、乱数ジェネレーターを使用できます)。実際にこれを行う必要がある場合。