【问题标题】:Finding the last element of a multidimensional array that meets a condition through recursion通过递归找到满足条件的多维数组的最后一个元素
【发布时间】:2017-01-11 21:21:21
【问题描述】:

我知道现实生活中递归的例子并不多。我想我今天找到了一个,我想以问答方式分享它,因为我觉得它很吸引人。

我正在为我的游戏使用Phaser 引擎。用户点击后,我需要找到用户点击的游戏元素。一旦有多个元素一个在另一个之上,这就会变得复杂。然后,我需要检查它们的渲染顺序并选择最高的元素。

在 Phaser 中,所有显示对象的根都是“世界”。所有现有元素要么是世界的直接子代,要么是子代的子代。这是一个以游戏世界为顶部的分支结构。子项按其渲染顺序排序,这意味着最后一个在顶部。

下面是一个例子,每个显示对象都用一个数字表示:

var world = [
    [
        18,
        3,
        [
            1,
            14,
            2
        ],
        5,
        9,
        [
            3,
            5
        ]
    ],
    [
        16,
        7
    ]
];

这个数组共有三个级别,有两个主要的“组”。在游戏术语中,第二组添加在第一组之后,因此它呈现在顶部。在第一个组内,最后一个元素呈现在顶部,这是一个组。在该组内,最后一个元素再次呈现在顶部,依此类推。在所有这些元素中,最顶部呈现的是7,因为它是最后一个。

假设我单击鼠标,它恰好位于由大于 10 的数字表示的所有元素之上(181416)。我需要的是16,因为它位于最下方。

我如何获得它?

【问题讨论】:

    标签: javascript arrays recursion rendering


    【解决方案1】:

    您可以将Array#forEach 与递归方法一起使用。

    function getValue(array, cb) {
        var last;
        array.forEach(function iter(a) {
            if (Array.isArray(a)) {
                a.forEach(iter);
                return;
            }
            if (cb(a)) {
                last = a;
            }
        });
        return last;
    }
    
    function check(v) {
        return v > 10;
    }
    
    var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]];
    
    console.log(getValue(world, check));

    带有Array#reduce 和回调闭包的版本。

    function getLastValue(cb) {
        return function iter(r, a) {
            return Array.isArray(a) ? a.reduce(iter, r) : cb(a) ? a : r;
        };
    }
    
    function greaterThan10(v) {
        return v > 10;
    }
    
    var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]];
    
    console.log(world.reduce(getLastValue(greaterThan10), null));

    附录受 4castle 的 answer 启发,从后面迭代,并在第一次发现时尽早返回。

    function getValue(array, cb) {
        var i = array.length, r;
        while (i--) {
            if (Array.isArray(array[i])) {
                r = getValue(array[i], cb);
                if (r !== undefined) {
                    return r;
                }
            }
            if (cb(array[i])) {
                return array[i];
            }
        };
    }
    
    function check(v) {
        return v > 10 && v < 16;
    }
    
    var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]];
    
    console.log(getValue(world, check)); // 14

    【讨论】:

    • 关于第一个sn-p——使用Array.forEach()有什么好处?如果我使用它,我还需要检查当前对象是否为数组以避免在数字上调用它。如果我尝试循环一个数字,则使用 for 循环,它的长度将是未定义的,并且不会进行循环。我想如果存在length 可能会有问题,但它实际上并不是一个数组。关于第二个 sn-p - 你能解释一下它是如何工作的吗?我以前从未见过reduce(),我正在努力弄清楚会发生什么。不过我喜欢这段代码。
    • 您可以在调用函数之前添加完整性检查,或者如果没有提供正确的类型则返回。 reduce 迭代一个数组,接受一个回调并作为一个选项作为起始值。然后它根据给定或最后一个值和实际值返回一个新值。在这种情况下,回调接受一个比较函数greaterThan10 并返回一个函数iter 作为返回的回调。在函数内部,它检查数组并返回减少值或检查值。减少的另一个原因是,你可以写出很酷的句子。
    • 对于这个问题,为什么forEach,它只是一个传统的方法,带有一个外部变量来保持结果。
    【解决方案2】:

    要获取满足某些条件的多维数组的最后一个元素,您应该使用某种检查来确保元素是否为数组,以便您知道是否进行递归调用.可以使用 Array.isArray 来确定某个东西是否是数组,或者您可以使用鸭子类型并检查 length 属性。

    在数组上向后循环将帮助您更快地找到顶部元素。

    function topElement(condition, array) {
      for (var i = array.length - 1; i >= 0; i--) {
        var val = array[i];
        if (Array.isArray(val)) {
          var top = topElement(condition, val);
          if (top !== undefined) {
            return top;
          }
        } else if (condition(val)) {
          return val;
        }
      }
      return undefined;
    }
    
    function check(num) {
      return num > 10;
    }
    
    var world = [[18, 3, [1, 14, 2], 5, 9, [3, 5]], [16, 7]];
    console.log(topElement(check, world));

    【讨论】:

      【解决方案3】:
      function topElement(fn, object, data) {
          if (fn(object) === true) {
              data = object;
          }
      
          for (var i = 0; i < object.length; i++) {
              data = topElement(fn, object[i], data);
          }
      
          return data;
      }
      
      function check(num) {
          return (num > 10);
      }
      
      topElement(check, world); // 16
      

      如果我想要不同的条件,我会更改 check() 方法。在我的游戏中,不同的条件是用户点击的地方。 check() 将游戏元素与点进行比较,如果它在其中,则返回 true,然后 topElement() 返回满足条件的渲染顺序最下方的元素。

      这是fiddle

      【讨论】:

        猜你喜欢
        • 2017-01-03
        • 2012-01-14
        • 1970-01-01
        • 1970-01-01
        • 2020-10-16
        • 1970-01-01
        • 2019-06-12
        • 1970-01-01
        • 2013-05-28
        相关资源
        最近更新 更多