将C# 3D数组移植到JS 3D数组

7
我开发了一个用于三个项目的C#库,这个库中包含特定代码段。但是,在JavaScript中我仍需要使用该代码,因此我正在进行移植。问题是,我不认为我能够重复相同的逻辑。例如,我已经思考了几天,但是仍然找不到答案。
在C#库中,我有一个3D数组,它类似于应用程序中的核心属性,但我无法弄清楚如何在JS环境下运行它。
例如,我有这段代码:
public Obj[,,] objs = new Obj[18, 14, 8];

我想在每个位置上分配对象,试图将其移植到JavaScript中似乎会导致:

var 3dArr = new Array();
    3dArr[0] = new Array();
    3dArr[0][0] = new Array();

这样做会始终将数组对象保留在第一个位置,如果我设置其他内容,那么整个数组都会丢失吗?或者我错了吗。

1
你是正确的。在JS中没有内置类型来表示多维数组。 - zerkms
1
你可以用JS构建嵌套数组,就像在C#中描述的 public Obj[ Obj[ Obj[] ] ] objs。或者你可以创建一个适配器,使用API将n维位置映射到内部数据结构的一维键/索引。例如 key = [x,y,z].join('::')index = (x*14+y)*8+z。当然需要加上验证,确保位置不越界。 - Thomas
4个回答

2
在撰写本文时,JavaScript中没有类似于C#中的多维数组的语言特性。同时,也不建议将普通数组暴露给整个应用程序使用,因为这样很容易通过向数组写入不应该包含的内容而错误地破坏整个代码。
然而,将所需的数组封装到一个简单的新类(例如下面的Array3d)中应该相对容易:

/***** CODE OF THE ARRAY *****/
function Array3d(width, height, depth, type) {
    this.width = width;
    this.height = height;
    this.depth = depth;
    this.type = type;
    this.array = new Array(width * height * depth);
}

Array3d.prototype = {
    get: function(x, y, z) {
        return this.array[calcIndex(this, x, y, z)];
    },
    set: function(x, y, z, item) {
        if (!(item instanceof this.type)) {
            throw new Error(item + ' is not instance of ' + this.type + '.');
        }
        this.array[calcIndex(this, x, y, z)] = item;
    }
};

function calcIndex(array3d, x, y, z) {
    return x + array3d.width * y + array3d.width * array3d.height * z;
}

/***** USAGE CODE *****/
function Something(i) {
    this.index = i;
}

var array3d = new Array3d(10, 11, 12, Something);
var something = new Something(11);
array3d.set(4, 0, 0, something);
var gettingBack = array3d.get(4, 0, 0);
if (gettingBack === something) {
    console.log('1: Works as expected');
}
else {
    console.error('1: Not expected ' + gettingBack);
}
gettingBack = array3d.get(0, 0, 4);
if (gettingBack == null) {
    console.log('2: Works as expected');
}
else {
    console.error('1: Not expected ' + gettingBack);
}


1
是的,我考虑过根据x、y和z坐标计算对象位置的方法,只是想确保我百分之百确定不能使用array[x, y, z]来实现它。 你的答案似乎是正确的。我会尝试并测试一下。谢谢! - Diego Zamonsett

1
尝试这个...
Array3d = function (width, height, depth, defaultValue) {
   width = width || 1;
   height = height || 1;
   depth = depth || 1;
   defaultValue= defaultValue|| 0;
   var arr = [];
   for (var i = 0; i < width; i++) {
      arr.push([]);
      for (var j = 0; j < height; j++) {
         var last = arr[arr.length - 1];
        last.push([]);
        for (var k = 0; k < depth; k++) {
            last[last.length - 1].push(defaultValue);
        }
      }
   }
   return arr;
}
console.log(new Array3d(3, 5, 2, 0));

所以,指定widthheightdepth(这三个默认为1)和defaultValue(默认为零),您就可以像操作任何javascript数组一样操作它...

1
在 JavaScript 中,一个三维数组被创建为一个数组的数组的数组:
var 3DArr = [[[],[],[]],[[],[],[]],[[],[],[]]];

现在3DArr是一个包含数组的数组,每个数组也包含数组。因此,您可以执行以下操作(例如):

3DArr[0][1].push(10);
console.log(3DArr); // [[[],[10],[]],[[],[],[]],[[],[],[]]]

0
在新的浏览器中,可以使用Array.from初始化数组的数组:

a = Array.from(Array(3), () => Array.from(Array(3), () => Array(3).fill(0)))

console.log(JSON.stringify(a))

作为一个旁注,JavaScript 中的“数组”更像是一种特殊的 字典,它使用整数键来存储数据。

a = []
a['1'] = 2
a.b = 'c'
a[3.14] = Math.PI

console.log(a)                    // "[undefined, 2]"
console.log(a[1], a.b, a['3.14']) // "2 c 3.141592653589793"

因此,在初始化所有“维度”之前,您可以为其分配值:

function set(a, x, y, z, v) {
  if(!a[x]) a[x] = []
  if(!a[x][y]) a[x][y] = []
  a[x][y][z] = v
}

a = []
set(a, 1, 2, 3, 4)

console.log(a)


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