2

我有一个这样的数组:

["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'
]

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

4

3 回答 3

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);

演示

于 2013-02-06T08:24:44.747 回答
1

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

例如,给定

["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"

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

于 2013-02-06T08:05:58.093 回答
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());
于 2013-02-06T10:39:14.410 回答