0

I am learning to code. I am using Unity and C#, and I am finding some difficulties trying to create and populate multiple array though a for loop.

In other languages you could do something like this:

for (int j = 0; j <= 3; j++)
    {
     scenes[j] = new float[2] {test[j], test2[j] };
    }

But apparently I cannot do something similar in C#. Is that right?

How should I do then?

I need something that create something like this:

scenes1 = {x1, y1}
scenes2 = {x2, y2}

and so on...

  • please expand your code sample with definitions of `scenes`, `test` and `test2` so we can know their types. Also specific compiler error might be helpful. – SergGr Feb 25 '17 at 04:19
  • Basically here is my issue. In my program,I have different scenes,inside this scenes, I also need to change one variable. I have 8 scenes, and 5 highs I would like to randomly select 1 scene with 1 high, in a way that I have all the possible combinations, random, and non-repeated. I created two different arrays, I shuffle the scenes array, and then through a for loop, I take one scene and 1 high. The problem is that I have random scenes but the highs will always be in the same order, and if I shuffle also the highs, obviously I don't have anymore a balanced combinations of variables. – CornelioQuinto Feb 25 '17 at 04:25
  • so was I was trying to do was to use a function to create a combination of two arrays and then create 40 new arrays of length = 2 dinamically, each array would have been one of my combination.. sounds pretty stupid, but probably reading the message above, there could be a more clever solution – CornelioQuinto Feb 25 '17 at 04:26
  • Actual code is worth thousands of words. Please, extend your code with actual type definitions. – SergGr Feb 25 '17 at 04:28
  • Creating an arrays populated with 1,2,3,4... Float scene = new Float[8]; for(int j = 0; j < 8; j++){ scene[j] = scene[j]; }. There is a random functions in C# . Create a random index from 1 to 8 Random r = new Random(); select One Scene randomly; scene[r.Next(1,8)]; this will select only one scene. To select multiple scenes just put this code on the for loop. – Juniar Feb 25 '17 at 05:24

2 Answers2

0

Multi dimensional arrays may give you a solution to the problem, all of you data may go into a single array, in your case you may use structure like scenes['index or position', 'test', 'test2'], I am not well versed in C# (unfortunately) but you can see more here. Hope this helps.

  • Thanks Kudzai, I was thinking at that at some point, the problem is that I don't know how to take random elements from there in order to have all the combination without repetitions – CornelioQuinto Feb 25 '17 at 06:06
  • @CornelioQuinto To generate a random index from an array like test and test2 you could implement something like the [solution](http://stackoverflow.com/questions/2019417/access-random-item-in-list) to this problem, check it out and see if its helpful. –  Feb 25 '17 at 06:26
0

Basing on your answers in comments I still don't understand what exactly you need. AFAIU you have two pieces of data: scenes and heights; and you want to generate permutations of compound (scene, height) elements. I assume that you either need:

  1. Generate a random list of all possible permuations exactly once

  2. Generate a long (possibly infinite) stream of random different permuations

So here is some code that might help.

First let's define some boilerplate:

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

Of course your Scene class is most probably more complicated. CompoundSceneData is a struct representing single item of scene + height.

#1 Generate a random list of all possible permuations exactly once:

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

There are a few key ideas there:

  • If we have N scenes and M heights there will be NM permutations and given a number in range [0, NM-1] you can select a pair. For example, 2*N + 5 means 5-th scene + 2-nd height (in 0-based indices(!)).

  • Thus if we want to generate a sequence of different pairs of N scenes and M heights, it is enough to generate a random permuation of numbers [0, N*M-1] and use it as sequence of indices

  • There is a well known Fisher–Yates shuffle algorithm to create a random permutation.

#2 Generate an infinite stream of random different 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);
        }
    }

The only interesting thing here is a usage of a C# feature yield return. This feature allows creating streams of data (IEnumerable) from code that looks sequential.

Note that for the solution #2 there is no guarantee that each combination (scene+data) will occur only once per (N*M) items. It just generates random combinations that will have good statistical properties only in long run. It is possible to achieve this guarantee as well but it significantly complicates the code and probably the user will not notice anyway.

SergGr
  • 23,570
  • 2
  • 30
  • 51