负数索引数组

4
我有一个数组,用于存储我正在开发的游戏地图数据。
MyMapType[,,] map; 

我使用固定数组而不是集合的原因是因为固定数组的速度非常快。
现在我的问题是,我想在游戏中支持负 z 级别。所以我想能够访问负索引。
如果这不可能,我考虑了一对其他解决方案。
我考虑作为可能的解决方案,将地面级别设为某个任意数(比如10),任何小于10的数都可以被视为负数。但是如果没有使用,这是否会使数组变大10倍?
我考虑的另一个解决方案是“自己编写”,其中您拥有 2D 数组的字典,Z 级别在列表中作为索引。但是这需要更多的工作,而且我不确定它是否慢。
总之 - 是否有创建支持负索引的数组的方法?如果没有 - 是否有一种干净的“模拟”此类行为的方法,而不会牺牲太多 CPU 时间或 RAM - 注意这些是可能变得很大并需要不断访问的游戏地图。

将10个额外元素添加到数组中并不会使其增加一个数量级(除非该数组最初只有约1个元素)。 - Matt Ball
4
如果你想要速度,多维数组不是一个好的选择。它们比单维数组慢得多。如果你构建的地图数据大部分都是空间或具有大量冗余,则不可变四叉树可能比数组更好;虽然访问速度较慢,但你可以用相对较少的内存表示任意大的区域。而且它们很容易支持负索引。 - Eric Lippert
话虽如此,这个问题并不适合在该网站上提问。请尝试提出一个关于实际代码的具体问题。 - Eric Lippert
1
@Haedrian:它们是单维数组,使用简单的数学方法来获取正确的记录。但是这个数学计算是由一个辅助方法完成的,这会导致开销。如果你对它进行分析,你会发现在.NET中,与其他变量访问相比,多维数组访问速度相当慢。 - Eric Lippert
1
可能是重复的问题:如何实现带负索引的数组 - nawfal
显示剩余4条评论
5个回答

10

用类替换你的数组:

class MyArray {
    private MyMapType[] myArray = new myMapType[size]
    MyMapType this[index] {
       get{return myArray[index + offset];}
    }

}

你可以在构造函数中设置大小和偏移量,甚至可以随意更改。

在此示例的基础上,这里是另一个版本:

class MyArray {
    private MyMapType[] positives = new myMapType[size]
    private MyMapType[] negatives = new myMapType[size-1]
    MyMapType this[index] {
       get{return index >= 0 ? positives[index] : negateves[1-index];}
    }

}

这并不改变你需要为它们两个设置大小的事实。说实话,我更喜欢第一个。


这个解决方案将使他定义偏移量。 - aguyngueran
问题在于我需要一个多维数组。所以我需要重写一堆代码来获取第x个,第y个,第z个值。嗯。 - Haedrian
@aguyngueran 是的,但他无论如何都想这样做,而且这是不可避免的。定义偏移量与定义大小没有任何区别,如果你想要数组,那么你不能逃避这个问题。 - mfeingold
@Haedrian,考虑Eric Lippert的评论,将一维类数组考虑在内。 - mfeingold
嗯,我喜欢你的第二个方案,对于多维数组而言不会增加太多开销(如果我发现它太慢了,我会考虑像Eric Lippert建议的四叉树,但对于我的目的,我认为它足够快)。 - Haedrian

7
如果你想使用“负数”索引,C# 8 现在支持它。
var words = new string[]
{
                // index from start    index from end
    "The",      // 0                   ^9
    "quick",    // 1                   ^8
    "brown",    // 2                   ^7
    "fox",      // 3                   ^6
    "jumps",    // 4                   ^5
    "over",     // 5                   ^4
    "the",      // 6                   ^3
    "lazy",     // 7                   ^2
    "dog"       // 8                   ^1
};              // 9 (or words.Length) ^0

因此,调用负数的方法将会是这样的:

words[^1]

请参考此链接

因此,在你的情况下,中间元素可以是零Z。


3
我只想指出,调用words [^1]与调用words [8]是等价的,坦率地说,这与调用words [-1]不相等。 - user3915050

2

使用Dictionary类,因为您可以为键或值分配任何值。虽然我不确定这如何适用于您上面展示的三维数组,但如果这是一个一维数组,我可以展示它的使用方法,您可以推断出如何最好地利用它:

MyMapType[] map;

//map is filled with w/e data

Dictionary<int, MyMapType> x = new Dictionary<int, MyMapType>();

x[-1] = //(map data for whatever value is for the negative value);
x[0] = map[0]
//(etc...)

我有完全相同的想法。但是我只需要一个可以双向移动的 1维 数组。可以使用3D数组实现:Dictionary<int,Dictionary<int,Dictionary<int,MyMapType>>>> - Bitterblue
我发现这是一个很好的解决方案!我有一个需要支持负索引的二维数组(网格)。从 Cell[,] 切换到 Dictionary<(int, int), Cell> 给了我我所需要的东西。 - devklick

1

请尝试将MyMapTime[,]列表存储在两个列表中:

  • 一个用于大于或等于0的z值
  • 另一个用于负z值。

表的索引将是z的值。这将使您快速访问特定z级别的xy值。当然问题是:您的z值是什么?它们是稀疏还是密集的。即使对于稀疏值,您最终也会得到一个包含[, ]空值的数组。


-1

在这里我想指出字典允许使用负索引,而且一个二维字典也可以解决这类问题,只需考虑数据结构并确定是否可以使用字典。

请注意,字典和列表用于不同的场景。它们的速度取决于所使用的函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接