根據你在評論中的回答,我仍然不明白你到底需要什麼。 AFAIU你有兩件數據:場景和高度;並且您想要生成複合(場景,高度)元素的排列。我認爲你要麼需要:
生成所有可能的permuations的恰好一次
隨機列表隨機生成不同permuations
長(可能是無限的)流所以在這裏是一些可能有用的代碼。
首先讓我們定義一些樣板:
public class Scene
{
public readonly string Something;
public Scene(string something)
{
Something = something;
}
// something else
}
public struct CompoundSceneData
{
public readonly Scene Scene;
public readonly float Height;
public CompoundSceneData(Scene scene, float height)
{
Scene = scene;
Height = height;
}
}
當然你Scene
類是最有可能更爲複雜。 CompoundSceneData
是一個表示場景+高度的單個項目的結構。
#1生成所有可能的permuations隨機列出恰好一次:
// Fisher–Yates shuffle of indices 0..size
int[] GenerateRandomIndicesPermutation(int size)
{
int[] permutation = Enumerable.Range(0, size).ToArray();
Random rnd = new Random();
for (int cur = size; cur >= 2; cur--)
{
int swapPos = rnd.Next(cur);
int tmp = permutation[swapPos];
permutation[swapPos] = permutation[cur - 1];
permutation[cur - 1] = tmp;
}
return permutation;
}
List<CompoundSceneData> GenerateAllRandomPermutationsOnce(Scene[] scenes, float[] heights)
{
int scenesCount = scenes.Length;
int heightsCount = heights.Length;
int totalCount = scenesCount * heightsCount;
List<CompoundSceneData> permutations = new List<CompoundSceneData>(totalCount);
foreach (var compoundIndex in GenerateRandomIndicesPermutation(totalCount))
{
int sceneIndex = compoundIndex % scenesCount;
int heightIndex = compoundIndex/scenesCount;
permutations.Add(new CompoundSceneData(scenes[sceneIndex], heights[heightIndex]));
}
return permutations;
}
void TestUsageAllOnce()
{
Scene[] scenes = new Scene[] { new Scene("Scene #1"), new Scene("Scene #2") };
float[] heights = new float[] { 0.1f, 0.2f, 0.3f };
// this is effectively endless loop
foreach (CompoundSceneData sceneData in GenerateAllRandomPermutationsOnce(scenes, heights))
{
// will be called excactly 2*3 = 6 times
DrawScene(sceneData);
}
}
有幾個關鍵概念有:
如果我們有N個場景和M的高度有將是N M置換,並給定範圍[0,N M-1]中的數字,您可以選擇一對。例如,2 * N + 5表示第5個場景+第2個高度(在基於0的索引(!)中)。
因此,如果我們想要生成N個場景和M個高度的不同對的序列,那麼足以生成數字[0,N * M-1]的隨機序列並將其用作指數序列
有一個衆所周知的Fisher–Yates shuffle算法來創建一個隨機排列。
#2隨機生成不同permuations無限流:
IEnumerable<CompoundSceneData> GenerateInfiniteRandomStream(Scene[] scenes, float[] heights)
{
Random rnd = new Random();
while (true)
{
int sceneIndex = rnd.Next(scenes.Length);
int heightIndex = rnd.Next(heights.Length);
yield return new CompoundSceneData(scenes[sceneIndex], heights[heightIndex]);
}
}
void TestUsageInfinite()
{
Scene[] scenes = new Scene[] { new Scene("Scene #1"), new Scene("Scene #2") };
float[] heights = new float[] { 0.1f, 0.2f, 0.3f };
// this is effectively endless loop
foreach (CompoundSceneData sceneData in GenerateInfiniteRandomStream(scenes, heights))
{
DrawScene(sceneData);
// this is the only thing that will stop the loop
if (IsEndOfGame)
break;
}
}
void TestUsageInfinite2()
{
Scene[] scenes = new Scene[] { new Scene("Scene #1"), new Scene("Scene #2") };
float[] heights = new float[] { 0.1f, 0.2f, 0.3f };
List<CompoundSceneData> fixedSizeList = GenerateInfiniteRandomStream(scenes, heights).Take(100).ToList();
foreach (CompoundSceneData sceneData in fixedSizeList)
{
// this will be called 100 times (as specified in Take)
DrawScene(sceneData);
}
}
這裏唯一有趣的事情是一個C#的特徵yield return
的使用。該功能允許從看起來順序的代碼創建數據流(IEnumerable
)。
請注意,對於解決方案#2,不能保證每個組合(場景+數據)只會出現一次(N * M)個項目。它只是生成隨機組合,只有長期運行才具有良好的統計特性。也有可能實現這種保證,但它使代碼顯着複雜化,並且用戶可能不會注意到。
請使用'scenes','test'和'test2'的定義擴展您的代碼示例,以便我們可以知道它們的類型。另外,特定的編譯器錯誤可能會有幫助 – SergGr
基本上這是我的問題。 在我的程序中,我有不同的場景,在這個場景裏面,我也需要改變一個變量。 我有8個場景和5個高點 我想隨機選擇1個高1場景,以我擁有所有可能的組合,隨機和不重複的方式。 我創建了兩個不同的數組,我洗牌場景數組,然後通過for循環,我採取了一個場景和1高。問題是,我有隨機的場景,但高位將始終是相同的順序,如果我洗牌高位,顯然我不再有一個平衡的變量組合。 – CornelioQuinto
所以我試圖做的是使用一個函數來創建兩個數組的組合,然後創建40個新的數組長度= 2 dinamically,每個數組將會是我的組合之一..聽起來很愚蠢,但可能閱讀上面的消息,可能會有更巧妙的解決方案 – CornelioQuinto