如何优化以下js代码,通过缩进来获取路径的层级?

a
    b
        c
        k
    d
e
        f 
            h
    g
let str = `a
    b
        c
        k
    d
e
        f 
            h
    g`
const space_count = (str) => {
    return str.indexOf(str.trim())
}
const submit = () => {
    let p = str.trim().split("\n")
    // 父路径的每一项的名称
    let parentPathSplit = []
    // 合并后的路径列表
    let joinPath = []
    // 缩进的次数,4个空格为一个缩进
    let indentationCount = 0
    let trimPath = ""
    for (let item of p) {
        trimPath = item.trim()
        if (trimPath == "") {
            continue
        }
        indentationCount = Math.ceil(space_count(item) / 4)

        // 如果缩进的次数为0,说明顶层路径,重置parentPathSplit
        if (indentationCount == 0) {
            parentPathSplit = [trimPath]
            joinPath.push(parentPathSplit.join("/"))
            continue
        }
        // 缩进的次数与parentPathSplit对应,0是顶层,1是第二层...
        // 次数与长度相同,添加
        // 如果下一次还是相同的缩进,说明是并列关系,此时,长度 > 次数
        if (indentationCount == parentPathSplit.length) {
            parentPathSplit[indentationCount] = trimPath
            joinPath.push(parentPathSplit.join("/"))
            continue
        }
        // 如果父级是1个缩进,当前为3个缩进,多了一个,以下代码修正这种问题
        if (indentationCount > parentPathSplit.length) {
            indentationCount = parentPathSplit.length
            parentPathSplit[indentationCount] = trimPath
        }
        // 合并父目录及当前路径
        joinPath.push(parentPathSplit.slice(0, indentationCount).join("/") + "/" + trimPath)
    }
    console.log(joinPath)
}

输出:

[
    "a",
    "a/b",
    "a/b/c",
    "a/b/k",
    "a/d",
    "e",
    "e/f",
    "e/f/h",
    "e/g"
]

代码能走通,结果也正常,问题是优化,可能还有未顾及到的地方。
谢谢

阅读 1.4k
avatarAI BotBETA

优化上述JavaScript代码的关键在于简化逻辑,减少不必要的计算和中间变量,并确保代码易于理解和维护。以下是一些可能的优化措施:

  1. 避免在循环中重复调用trim
    我们可以只调用一次trim,并将结果存储在变量中,以避免在每次迭代时重复调用它。
  2. 减少计算量
    space_count函数在每次迭代中都被调用,并且它内部又使用了indexOf,这可能会导致不必要的性能开销。我们可以尝试直接计算缩进量,而不是通过查找第一个非空格字符的位置来间接计算。
  3. 简化路径构建逻辑
    当前逻辑在处理缩进级别变化时较为复杂。我们可以使用一个栈来简化这个过程,栈中的每个元素表示当前路径的一个部分。
  4. 使用Array.prototype.mapfor...of循环
    根据代码的当前形式,for...of循环是合适的,但如果需要更简洁的代码,可以考虑使用map方法。
  5. 添加错误处理和边界检查
    对于输入字符串的格式,应该添加一些错误处理来确保代码的健壮性。

基于以上建议,以下是一个优化后的代码示例:

function parseIndentedText(str) {
    const lines = str.trim().split('\n');
    const pathStack = []; // 用于存储当前路径的栈
    const result = []; // 存储最终结果的数组
    const indentSize = 4; // 缩进大小,这里假设为4个空格

    for (const line of lines) {
        const trimmedLine = line.trim();
        if (trimmedLine === '') continue; // 跳过空行

        const indentLevel = Math.floor(line.search(/\S|$/) / indentSize); // 直接计算缩进级别

        // 如果当前行的缩进级别小于栈的大小,说明需要回退到上一个路径级别
        while (pathStack.length > indentLevel) {
            pathStack.pop();
        }

        // 添加当前项到路径栈中
        pathStack.push(trimmedLine);

        // 将栈中的路径元素合并成字符串并添加到结果数组中
        result.push(pathStack.join('/'));
    }

    return result;
}

// 测试代码
const str = `a
    b
        c
        k
    d
e
        f 
            h
    g`;
const output = parseIndentedText(str);
console.log(output);

这个优化后的代码使用了栈来跟踪当前的路径级别,并直接计算每行的缩进级别,从而避免了在循环中多次调用trimindexOf。此外,代码的结构也更加清晰和简洁。

2 个回答
let str = `a
    b
        c
        k
    d
e
        f
            h
    g`;

const lines = str.split("\n")
    .map(line => ({
        // 通过空格数计算层级
        level: ~~((line.length - line.trimStart().length) / 4),
        value: line.trim()
    }));

// e 和 f 之间的层级差出现了越级的情况,修正 level,方便后面的 path 算法
lines.reduce((level, it) => {
    if (it.level - level > 1) {
        it.level = level + 1;
    }
    return it.level;
}, 0);

// 这部分算法不想解释了,自己跟吧
// 主要目的就是用 path 保存处理过程,循环事更新对应层次,
//      并截取(段)组合成路径字符串
const path = [];
const result = [];
for (const it of lines) {
    const { level, value } = it;
    path[level] = value;
    result.push(path.slice(0, level + 1).join("/"));
}

console.log(JSON.stringify(result, null, 4));

结果

[
    "a",
    "a/b",
    "a/b/c",
    "a/b/k",
    "a/d",
    "e",
    "e/f",
    "e/f/h",
    "e/g"
]

代码

str.split('\n')
   .reduce((arr, item) => {
      arr[0].splice(item.search(/\S/) / 4, Infinity, item.trim())
      arr.push(arr[0].join('/'))
      return arr
   }, [[]])
   .slice(1)

结果

[
  "a",
  "a/b",
  "a/b/c",
  "a/b/k",
  "a/d",
  "e",
  "e/f",
  "e/f/h",
  "e/g"
]
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题