我有一個串列,轉換成 js 陣列。幾行有一個制表符前綴:
var data = [
"2",
" 2.1",
" 2.1.1",
" 2.2",
"3",
"4"
]
我想要做的是得到以下結構:
var data = [
"2",
"2->2.1",
"2->2.1->2.1.1",
"2->2.2",
"3",
"4"
]
試過(產生錯誤的結果):
for (var i = 0; i < data.length; i ) {
var current = data;
var length = data[i].length - data[i].replaceAll(" ", "").length;
if (!length) {
console.log(current);
} else {
console.log(data[i-1] '->' data[i].trim());
}
}
更新(@MustSeeMelons) - 您的解決方案在下面附加的測驗資料上產生錯誤的結果:

uj5u.com熱心網友回復:
平到樹
我在這個問答中解決了這個問題。我們可以在您的資料上重復使用相同的功能 -
const data = `
2
2.1
2.1.1
2.2
3
4
`
// using makeChildren and sanitize from the linked Q&A
console.log(makeChildren(sanitize(data)))
[
{
"value": "2",
"children": [
{
"value": "2.1",
"children": [
{
"value": "2.1.1",
"children": []
}
]
},
{
"value": "2.2",
"children": []
}
]
},
{
"value": "3",
"children": []
},
{
"value": "4",
"children": []
}
]
樹變平
現在剩下的就是將樹轉換為paths-
function* paths(t) {
switch (t?.constructor) {
case Array:
for (const child of t)
yield* paths(child)
break
case Object:
yield [t.value]
for (const path of paths(t.children))
yield [t.value, ...path]
break
}
}
const result =
Array.from(paths(makeChildren(sanitize(data))), path => path.join("->"))
[
"2",
"2->2.1",
"2->2.1->2.1.1",
"2->2.2",
"3",
"4"
]
優點
將問題分解成更小的部分可以更容易地解決并產生可重用的功能,但這些并不是唯一的優勢。中間樹表示使您能夠在平面表示不允許的樹的背景關系中進行其他修改。此外,該paths函式產生路徑段陣列,允許呼叫者決定需要哪種最終效果,即path.join("->"),或其他。
演示
運行下面的演示,在您自己的瀏覽器中驗證結果 -
const sanitize = (str = "") =>
str.trim().replace(/\n\s*\n/g, "\n")
const makeChildren = (str = "") =>
str === ""
? []
: str.split(/\n(?!\s)/).map(make1)
const make1 = (str = "") => {
const [ value, children ] = cut(str, "\n")
return { value, children: makeChildren(outdent(children)) }
}
const cut = (str = "", char = "") => {
const pos = str.search(char)
return pos === -1
? [ str, "" ]
: [ str.substr(0, pos), str.substr(pos 1) ]
}
const outdent = (str = "") => {
const spaces = Math.max(0, str.search(/\S/))
const re = new RegExp(`(^|\n)\\s{${spaces}}`, "g")
return str.replace(re, "$1")
}
function* paths(t) {
switch (t?.constructor) {
case Array: for (const child of t) yield* paths(child); break
case Object: yield [t.value]; for (const path of paths(t.children)) yield [t.value, ...path]; break
}
}
const data = `\n2\n\t2.1\n\t\n\t2.1.1\n\t2.2\n3\n4`
console.log(
Array.from(paths(makeChildren(sanitize(data))), path => path.join("->"))
)
.as-console-wrapper { min-height: 100%; top: 0; }
評論
outdent是通用的,無論您使用文字制表符\t \t\t \t\t\t...、 還是一些空格都可以使用。重要的是空格是一致的。查看原始問答,以更深入地了解每個部分的作業原理。
uj5u.com熱心網友回復:
有很多方法可以解決這個問題。
方法#1:
如果您被允許使用輔助空間,請創建一個陣列來跟蹤行的最新級別。它不基于分隔符。
let data = ["2","\t2.1","\t\t2.1.1","\t2.2","3","4"], tab="\t", latest = [];
let output = data.map(x => {
let noTabs = x.split(tab).length-1;
latest = [...latest.slice(0, noTabs), x.replaceAll(tab, '')];
return latest.join('->');
})
console.log(output)
uj5u.com熱心網友回復:
這幾乎可以滿足您的要求,但不確定您要如何對它們進行分組:
const mapped = data.reduce((acc, curr, idx) => {
if (idx !== 0) {
// Get leading digit of current & previous element
const current = curr.trim()[0];
const previous = acc[idx - 1].trim()[0];
// If leading match, aggregate them
if (current === previous) {
acc.push(`${acc[idx - 1].trim()}->${curr.trim()}`);
} else {
acc.push(curr.trim());
}
} else {
acc.push(curr.trim());
}
return acc;
}, []);
for除非您需要在某個時候跳出回圈,否則不要使用回圈。轉換陣列通常應該使用map函式來完成。我使用reduce這個問題是因為這個問題需要我訪問新的、已經映射的元素。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/489060.html
標籤:javascript 数组 列表 递归
上一篇:遞回遍歷嵌套的HTML串列
