【问题标题】:Create and populate multiple arrays with a for loop使用 for 循环创建和填充多个数组
【发布时间】:2017-02-25 03:55:46
【问题描述】:

我正在学习编码。我正在使用 Unity 和 C#,但在尝试通过 for 循环创建和填充多个数组时发现了一些困难。

在其他语言中,您可以这样做:

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

但显然我不能在 C# 中做类似的事情。对吗?

那我该怎么办?

我需要一些东西来创造这样的东西:

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

等等……

【问题讨论】:

  • 请使用scenestesttest2 的定义扩展您的代码示例,以便我们知道它们的类型。特定的编译器错误也可能会有所帮助。
  • 基本上这是我的问题。在我的程序中,我有不同的场景,在这个场景中,我还需要更改一个变量。我有 8 个场景和 5 个高点我想随机选择 1 个场景和 1 个高点,这样我就有了所有可能的组合,随机且不重复。我创建了两个不同的数组,我打乱了场景数组,然后通过一个 for 循环,我取了一个场景和 1 个高点。问题是我有随机场景,但高点总是按相同的顺序排列,如果我也洗牌高点,显然我不再有平衡的变量组合。
  • 所以我试图做的是使用一个函数来创建两个数组的组合,然后动态创建 40 个长度 = 2 的新数组,每个数组都是我的组合之一。听起来很愚蠢,但可能阅读上面的消息,可能会有更聪明的解决方案
  • 实际代码价值数千字。请使用实际的类型定义扩展您的代码。
  • 创建一个填充有 1,2,3,4 的数组... Float scene = new Float[8]; for(int j = 0; j

标签: arrays loops dynamic-programming


【解决方案1】:

多维数组可能会给你一个解决问题的方法,你所有的数据都可以放在一个数组中,在你的情况下,你可以使用像场景['index or position', 'test', 'test2'] 这样的结构,我不精通 C#(不幸的是)但你可以看到更多 here。希望这会有所帮助。

【讨论】:

  • 谢谢 Kudzai,我当时在想,问题是我不知道如何从那里获取随机元素以便在没有重复的情况下进行所有组合
  • @CornelioQuinto 要从像 test 和 test2 这样的数组生成随机索引,您可以针对这个问题实现类似 solution 的东西,检查它是否有帮助。
【解决方案2】:

根据您在 cmets 中的答案,我仍然不明白您到底需要什么。 AFAIU 你有两条数据:场景和高度;并且您想要生成复合(场景,高度)元素的排列。我假设您需要:

  1. 只生成一次所有可能排列的随机列表

  2. 生成一个长的(可能是无限的)随机不同排列的流

所以这里有一些代码可能会有所帮助。

首先让我们定义一些样板:

    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只生成一次所有可能排列的随机列表:

    // 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 个高度,则会有 NM 个排列,并且给定一个范围为 [0, NM-1] 的数字,您可以选择一对。例如,2*N + 5 表示第 5 个场景 + 第 2 个高度(在从 0 开始的索引中(!))。

  • 因此,如果我们要生成一系列不同的 N 个场景和 M 个高度的序列,生成数字 [0, N*M-1] 的随机排列并将其用作索引序列就足够了

  • 有一种众所周知的Fisher–Yates shuffle 算法可以创建随机排列。

#2 生成无限的随机不同排列流:

    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) 个项目中只会出现一次。它只是生成随机组合,这些组合仅在长期内具有良好的统计特性。也可以实现这种保证,但它会使代码变得非常复杂,并且用户可能无论如何都不会注意到。

【讨论】:

    猜你喜欢
    • 2017-02-26
    • 1970-01-01
    • 2018-12-08
    • 2014-04-09
    • 2015-02-04
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多