数组递归开始结束点

时间:2013-02-06 07:54:49

标签: javascript loops recursion

我有一个这样的数组:

["one", "foo", "two", "baz", "two", "one", "three", "lulz", "wtf", "three"]
   1             2             2      1       3                       3

每个字符串都是访问对象文字的键。我想要做的是在这种情况下onetwothree前面加上由主键分隔的子键的完整路径。这是预期的结果:

[
  'one', 'one.foo', 'one.two', 'one.two.baz', 'one.two', 'one',
  'three', 'three.lulz', 'three.wtf', 'three'
]

过去几个小时我一直在尝试循环并首先提取重复的项目,然后尝试按给定的起点和终点切片。然后我尝试使用正则表达式,只是为了看看它是否可行但JS不处理正则表达式中的递归,它变得非常复杂并且可能是不必要的。我就是在那个地方,我感到沮丧,没有任何工作。我不知道现在去哪里。我被卡住了。

编辑:我已经尝试了一段时间了,因为它似乎更简单但理想情况下我想提取的是没有关闭“标签”的键链。

[
  'one', 'one.foo', 'one.two', 'one.two.baz',
  'three', 'three.lulz', 'three.wtf'
]

有人可以在这里启发我吗?

3 个答案:

答案 0 :(得分:2)

如果没有递归,你可以像这样解决它;它保留了一个公共前缀,并且在每次迭代时都会向左和向右扫描以查找相同的项目。

如果左侧有相同的项目,请减少前缀(在发出之前);如果右边有一个项目,请增加前缀(在发出后)。

var a = ["one", "foo", "two", "baz", "two", "one", "three", "lulz", "wtf", "three"];

var prefix = '',
    keys = [];

for (var i = 0, len = a.length; i < len; ++i) {
  var left = a.indexOf(a[i]),
      right = a.indexOf(a[i], i + 1);

  if (left >= 0 && left < i) {
    prefix = prefix.substr(0, prefix.lastIndexOf(a[i]));
  }
  keys.push(prefix + a[i]);
  if (right !== -1) {
    prefix = prefix + a[i] + '.';
  }
}

console.log(keys);

Demo

答案 1 :(得分:1)

你可以在这里避免递归。走完阵列吧。将当前数组元素与您正在累积的字符串进行比较。当您第一次看到新的“main”元素时,将其附加到您正在构建的字符串中。当你看到一个主要元素的结束实例与你到目前为止的字符串的后缀相匹配时,弹出它。在你走路时建立结果数组。

例如,给定

["one", "foo", "two", "baz", "two", "one", "three", "lulz", "wtf", "three"]

你首先看到“一个”所以发出那个

result = ["one"]
working = "one"

然后你会看到"foo"这样发出,但只保留"one"作为要比较的字符串。

result = ["one", "one.foo"]
working = "one"

接下来你有"two"所以发出并保持"one.two"

result = ["one", "one.foo", "one.two"]
working = "one.two"

接下来是"baz"发出但不保留。

result = ["one", "one.foo", "one.two", "one.two.baz"]
working = "one.two"

接下来是"two"所以你可以弹出!

result = ["one", "one.foo", "one.two", "one.two.baz"]
working = "one"

接下来,"one"再次弹出!

result = ["one", "one.foo", "one.two", "one.two.baz"]
working = ""

现在是一个三,这是一个主要标签,所以发出并保持:

result = ["one", "one.foo", "one.two", "one.two.baz", "three"]
working = "three"

爽快!我想你可以从这里拿走它。不需要花哨的递归。当然,您可能必须检查嵌套和平衡中的错误。

答案 2 :(得分:1)

这是一个递归解决方案。该函数采用当前前缀和它正在使用的数组。如果数组为空,它返回一个空数组的键,否则它通过从数组前面移动项目来构建具有当前前缀的键。如果在该过程中它到达数组的末尾,或者在数组中稍后出现的元素,它将停止构建新的键并进行递归。

递归通过在发现重复的元素的下一次出现时拆分数组来工作。当前密钥用作一个调用的左子数组的前缀,而另一个调用使用右子数组的空白前缀。该函数返回它找到的键加上两个递归调用找到的键。

不是最有效的解决方案,迭代的解决方案在这方面更好,但我想我会为任何感兴趣的人发布递归解决方案。

function foldKeys(prefix, arr) {
    var keys = [],
        key,
        i;

    if (arr.length == 0) {
        return keys;
    }

    do {
        next = arr.shift();
        key = prefix + (prefix == '' ?  next : ('.' + next));
        keys.push(key);
    } while (arr.length && (i = arr.indexOf(next)) === -1);

    return keys
        .concat(foldKeys(key, arr.slice(0, i)))
        .concat(foldKeys('', arr.slice(i + 1)));
}

var arr = ["one", "foo", "two", "baz", "two", "one", "three", "lulz", "wtf", "three"];
var keys = foldKeys('', arr);
console.log(keys.toString());