【问题标题】:Creating dynamically a finite n-dimensional coordinate system with integer coordinates from axial coordinates从轴向坐标动态创建具有整数坐标的有限 n 维坐标系
【发布时间】:2016-04-10 16:05:51
【问题描述】:

我试图通过首先创建轴向坐标来动态创建有限 n 维坐标系中的位置列表。系统只有整数作为坐标值。轴向坐标是 AxCrd 对象。 AxCrd 对象有两个属性:

  1. AxCrd.dim 是坐标尺寸的句柄或名称。例如,“x”或“y”。
  2. AxCrd.crd 是坐标值。它是一个整数。例如,-4 或 3。

我尝试编写一个函数,该函数接受所有生成的 AxCrd 对象作为输入,并输出我试图创建为 Crd 对象的 n 维空间中所有位置的列表。 Crd 对象有两个属性:

  1. Crd.dims 是一个数组,包含坐标的所有维度句柄。这个数组的长度为n,即等于维数。

  2. Crd.crds 是一个数组,包含上述维度的所有坐标值。该数组的顺序很重要,因为坐标的维度应该与坐标值具有相同的元素编号。 IE。如果维度“z”是第二个元素,则 crds[2] 是维度“z”的坐标值。

例如,假设我使用这些构造函数:

function AxCrd(dim,crd) { this.dim = dim, this.crd = crd }
function Crd(dims,crds) { this.dims = dims, this.crds = crds }

在我的实际预期用途中,大多数维度都有九个值:四个负数、四个正数和一个零。但为简洁起见,假设我有三个维度:

var input = [];
input.push(new AxCrd("x", -1));
input.push(new AxCrd("x", 1));
input.push(new AxCrd("y", -1));
input.push(new AxCrd("y", 1));
input.push(new AxCrd("z", -1));
input.push(new AxCrd("z", 1));
input.push(new AxCrd("d", -1));
input.push(new AxCrd("d", 1));

如您所见,共有三个维度,每个维度只有两个坐标值。我正在尝试编写一个函数,根据上述输入,它将创建新的 Crd 对象,如下所示:

var ret = [];
ret.push(new Crd(["x","y","z","d"],[-1,-1,-1,-1]));
ret.push(new Crd(["x","y","z","d"],[ 1,-1,-1,-1]));
ret.push(new Crd(["x","y","z","d"],[-1, 1,-1,-1]));
ret.push(new Crd(["x","y","z","d"],[ 1, 1,-1,-1]));
ret.push(new Crd(["x","y","z","d"],[-1,-1, 1,-1]));
ret.push(new Crd(["x","y","z","d"],[ 1,-1, 1,-1]));
ret.push(new Crd(["x","y","z","d"],[-1, 1, 1,-1]));
ret.push(new Crd(["x","y","z","d"],[ 1, 1, 1,-1]));
ret.push(new Crd(["x","y","z","d"],[-1,-1,-1, 1]));
ret.push(new Crd(["x","y","z","d"],[ 1,-1,-1, 1]));
ret.push(new Crd(["x","y","z","d"],[-1, 1,-1, 1]));
ret.push(new Crd(["x","y","z","d"],[ 1, 1,-1, 1]));
ret.push(new Crd(["x","y","z","d"],[-1,-1, 1, 1]));
ret.push(new Crd(["x","y","z","d"],[ 1,-1, 1, 1]));
ret.push(new Crd(["x","y","z","d"],[-1, 1, 1, 1]));
ret.push(new Crd(["x","y","z","d"],[ 1, 1, 1, 1]));

对于 n 维空间,我如何做到这一点?

【问题讨论】:

    标签: javascript arrays algorithm dynamic dimensions


    【解决方案1】:

    如果我理解您的问题,您需要将所有维度名称映射到它们的索引(称为 dim_map 应该是 dim_map['x'] = 0; dim_map['y'] = 1;...)。 然后,当您进行转换时,您可以将键用作 dims,查找 index = dim_map[AxCrd.dim] 的索引并将该值分配给相应的元素 (Crd.crds[index] = AxCrd.crd)。

    我不完全确定这是您想要的,因为您的示例似乎令人困惑。我不确定我为什么要为每个 AxCrd 构造两个 Crd,或者为什么其他一些值似乎会发生变化。

    【讨论】:

    • 在我正在创造的“游戏”或人工智能中,每个坐标都应该具有“道德价值”。您可能想将其视为“分数”。也就是说,玩家通过移动或被移动到某个坐标来获得某个分数。我想预先计算这些分数,以便更容易为计算机编写代码以找到最佳移动。我打算将预先计算的分数添加为 Crd 对象的属性。
    【解决方案2】:

    递归似乎是处理这类问题的正确方法。这是一个简单的递归函数,它返回点的数组作为结果。它还将维度的名称存储在作为函数参数传递的数组中。

    function rec(i, input, dimensions)
    {
       // find the name of the current dimension
       var currentd = input[i].dim;
    
       dimensions.push(currentd);
    
       // find how many elements in the current dimension
       var j = i;
       while (j < input.length && input[j].dim == currentd) ++j;
    
       // create a tail of results
       var tail = [];
       if (j < input.length) {
          tail = rec(j, input, dimensions);
       }
    
       // create a result by appending tail to all possible coordinates in the current dimension
       var result = [];
       for (; i < j; i++) {
           if (tail.length == 0) {
               result.push([input[i].crd]);
           } else {
               for (var k = 0; k < tail.length; k++) {
                   result.push([input[i].crd].concat(tail[k]));
               }
           }
       }
       return result;
    }
    

    这个函数不会像这样创建Crd 对象,但您可以轻松地对其进行修改。用法示例:

    var dimensions = [];
    var result = rec(0, input, dimensions);
    console.log(JSON.stringify(dimensions));
    for (var i = 0; i < result.length; i++) {
      console.log(JSON.stringify(result[i]));
    }
    

    输出(假设 input 与您的示例相同):

    ["x","y","z","d"]
    [-1,-1,-1,-1]
    [-1,-1,-1,1]
    [-1,-1,1,-1]
    [-1,-1,1,1]
    [-1,1,-1,-1]
    [-1,1,-1,1]
    [-1,1,1,-1]
    [-1,1,1,1]
    [1,-1,-1,-1]
    [1,-1,-1,1]
    [1,-1,1,-1]
    [1,-1,1,1]
    [1,1,-1,-1]
    [1,1,-1,1]
    [1,1,1,-1]
    [1,1,1,1]
    

    【讨论】:

      【解决方案3】:

      看起来好像您正在寻找每个子数组或Cartesian product 的项目的所有可能组合。这可以递归计算:

      function product(array) {
          if (array.length == 0) return [[]];
      
          var head = array[0];
          var tail = product(array.slice(1));
          var res = [];
      
          for (var i = 0; i < head.length; i++) {
              for (var j = 0; j < tail.length; j++) {
                  res.push([head[i]].concat(tail[j]));
              }
          }
      
          return res;
      }
      

      Ans 像这样使用它:

      var input = [
          [-1, 1],    // x
          [-1, 1],    // y
          [-1, 1],    // z
          [-1, 1],    // d
      ];
      
      var prod = product(input);
      
      for (var i = 0; i < prod.length; i++) {
          console.log(i, prod[i]);
      }
      

      上述函数的工作假设是传入的数组是一个数组数组。没有尝试检测到这一点。

      您可以将生成的数组添加到列表中,而不是打印。我不确定为什么每次添加坐标时都要创建一个新的坐标系。您不应该只创建一次坐标系并传递对它的引用吗?我还支持 Sorin,因为您可能需要一个用于逐个字母查找的地图。你的类设计似乎不必要地复杂。

      【讨论】:

        【解决方案4】:

        我打算做的事情似乎通过以下功能几乎可以实现:

        function makeAllCoordinates(arr) {
          if (arr.length === 0) { return []; }
          else if (arr.length === 1) { return arr[0]; }
          else {
            var result = [];
            var allCases = makeAllCoordinates(arr.slice(1));
            for (var c in allCases) {
              for (var i = 0; i < arr[0].length; i++) {
                result.push((arr[0][i] + allCases[c]).split(",")); }}
            return result; }}
        

        结果是一个由 9 × 9 × 9 × 9 × 3 × 3 = 59049 个成员组成的数组。这个数字是正确的。但是,每个数组只有一个成员,它是一个由六个重复的“[object Object]”组成的字符串。我需要它们是六个 AxCrd 对象的唯一数组,而不是这样的字符串。数组的顺序无关紧要。这样修改这个函数难吗?

        无论如何,我希望这个回复能消除我对我正在尝试做的事情的歧义。

        【讨论】:

        • 如果您将结果视为数组而不是字符串:result.push([arr[0][i]].concat(allCases[c]));?当您发布此答案时,其他两个答案已经发布了或多或少相同的代码。如果您只是想澄清一下,请编辑原始问题。 SO 允许您回答自己的问题,但前提是它们是真实且独特的解决方案。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-16
        • 2014-06-18
        • 2011-12-04
        • 2020-08-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多