這是我正在處理的平面物件,它有更多的結果,~6800。我一直在嘗試將它轉換為嵌套樹(如下面所列的樹)大約 13 個小時,我真的迷路了。
[
{
"make": "Acura",
"classification": "Mid SUV",
"segment": "Competitive Trucks",
"model": "RDX",
"catalogDetail": "RDX_SUV_4_Gasoline_2013_Base w/Tech_FWD_3.5_6_105.7_Automatic"
},
{
"make": "Acura",
"classification": "Midsize Car",
"segment": "Competitive Cars",
"model": "TSX",
"catalogDetail": "TSX_Sedan_4_Gasoline_2012_Base w/Tech_FWD_2.4_4_106.4_Automatic"
},
{
"make": "Aston Martin",
"classification": "Compact Car",
"segment": "Competitive Cars",
"model": "DB11",
"catalogDetail": "DB11_Convertible_2_Gasoline_2019_Volante_RWD_4.0_8_110.4_Automatic"
}
]
我想要做的是將這個平面物件構建成這樣的嵌套結構:
[
{
"make": [
{ "Acura",
"classification": [{
"Mid SUV",
"segment": [{
"Competitive Trucks",
"model": [{
"RDX",
"catalogDetail": [{
"RDX_SUV_4_Gasoline_2013_Base w/Tech_FWD_3.5_6_105.7_Automatic"
}]
}]
}],
"Midsize Car",
"segment": [{
"Competitive Cars",
"model": [{
"TSX",
"catalogDetail": [{
"TSX_Sedan_4_Gasoline_2012_Base w/Tech_FWD_2.4_4_106.4_Automatic"
}]
}]
}]
}],
}
]
},
{
"make": [
{ "Aston Martin",
"classification": [{
"Compact Car",
"segment": [{
"Competitive Cars",
"model": [{
"DB11",
"catalogDetail": [{
"DB11_Convertible_2_Gasoline_2019_Volante_RWD_4.0_8_110.4_Automatic"
}]
}]
}]
}]
}
]
}
]
其中結構屬于嵌套結構,如:制作 --> 分類 --> 細分 --> 模型 --> 目錄細節。所以會有多個汽車品牌,福特、凱迪拉克等。多個分類,每個品牌下有多個不同的細分市場。
這是我試過的:
this._servicesService.getHierarchy().subscribe(data => {
console.log(data)
/* this.data = data;*/
/* this.dataStore = data;*/
let distinctSeg = [...new Set(data.map(x => x.segment))];
let distinctClass = [...new Set(data.map(x => x.classification))];
let distinctMod = [...new Set(data.map(x => x.model))];
let distinctCd = [...new Set(data.map(x => x.catalogDetail))];
const newData = [];
data.forEach(e => {
if (newData.length == 0) {
newData.push({
make: e.make,
segment: e.segment,
classification: e.classification,
model: [e.model],
catalogDetail: [e.catalogDetail]
});
} else {
let foundIndex = newData.findIndex(fi => fi.make === e.make, fi => fi.segment = e.segment);
if (foundIndex >= 0) {
/* newData[foundIndex].make.push(e.make),*/
/* newData[foundIndex].segment.push(e.segment),*/
/* newData[foundIndex].classification.push(e.classification),*/
newData[foundIndex].model.push(e.model);
newData[foundIndex].catalogDetail.push(e.catalogDetail);
} else {
newData.push({
make: e.make,
segment: distinctSeg,
classification: distinctClass,
model: [e.model],
catalogDetail: [e.catalogDetail]
});
}
}
});
console.log(newData);
})
這為模型、段和類提供了不同的值(由于某種原因不是模型或目錄詳細資訊),但嵌套結構不存在,我真的不知道如何進行。我在這里查看了很多示例,但我確實沒有成功應用之前列出的任何路線。任何見解或提示將不勝感激。我附上了一張圖片以更好地可視化最終所需的輸出,以防我的語法錯誤。 樹
uj5u.com熱心網友回復:
我建議您為此使用Array.reduce方法。
這個方法可以讓你輕松地將一個js陣列轉換為一個物件。
您可以執行以下操作:
arr.reduce((accumulator, currentValue)=>{
if(!accumulator[currentValue.make]){
accumulator[currentValue.make] = []
}
accumulator[currentValue.make][0] = {...<PUT YOUR OBJECT VALUE HERE>}
},{})
uj5u.com熱心網友回復:
正如 Avrham 所說,您可以使用 reduce。想象一下你創建了一個函式
reduce(data:any[],key:string,keyArray:string)
{
return data.reduce((a:any[],b:any)=>{
const element=a.find(x=>x[key]==b[key])
const value=b[key]
delete b[key]
if (!element)
a.push({[key]:value,[keyArray]:[b]})
else
element[keyArray].push(b)
return a;
},[])
}
}
您可以使用以下方式:
const data=this.reduce(this.data,"make","classification")
data.forEach(x=>{
x.classification=this.reduce(x.classification,"classification","segment")
x.classification.forEach(c=>{
c.segment=this.reduce(c.segment,"segment","model")
c.segment.forEach(m=>{
m.model=this.reduce(m.model,"model","catalogDetail")
m.model.forEach(d=>d.catalogDetail=d.catalogDetail.map(e=>e.catalogDetail))
})
})
})
this.dataFormatted=data
但我認為管理這種樹視圖并不容易。一般來說,你有一個樹視圖,所有的陣列都是“孩子”。所以我建議創建一個函式
reduceChildren(data:any[],key:string)
{
return data.reduce((a:any[],b:any)=>{
const element=a.find(x=>x[key]==b[key])
const value=b[key]
delete b[key]
if (!element)
a.push({[key]:value,children:[b]})
else
element.children.push(b)
return a;
},[])
}
你可以使用像
const data=this.reduceChildren(this.data,"make")
data.forEach(x=>{
x.children=this.reduceChildren(x.children,"classification")
x.children.forEach(c=>{
c.children=this.reduceChildren(c.children,"segment")
c.children.forEach(m=>{
m.children=this.reduceChildren(m.children,"model")
m.children.forEach(d=>d.children=d.children.map(e=>e.catalogDetail))
})
})
})
this.dataFormatted=data
您可以在這個 stackblitz中看到這兩種方法
uj5u.com熱心網友回復:
看起來,對于輸入輸出,你想要這樣的東西:
const inp = [
{ a: "x", b: "u", c: "q" }, { a: "x", b: "v", c: "r" },
{ a: "x", b: "u", c: "s" }, { a: "x", b: "v", c: "t" },
{ a: "y", b: "u", c: "q" }, { a: "y", b: "u", c: "r" },
{ a: "y", b: "v", c: "s" },
];
const outp = collect(inp, "a", "b", "c");
console.log(outp);
// {x:{u: ["q","s"], v:["r","t"]}, y:{u:["q","r"], v:["s"]}}
其中collect()是一個函式,它接受一個物件陣列和這些物件的鍵串列。(它至少需要一個鍵,輸入物件應該string在這些鍵上有值。)我們的作業是實作collect().
我采用的方法是遞回的;首先,基本情況,您collect(inp, key1)只需要一把鑰匙。在這種情況下,我們只想回傳key1鍵值的陣列,我們可以通過mapping輸入陣列來獲得它;即inp.map(v => v[key1])。
然后是遞回步驟:當你collect(inp, key1, ...keyRest)用多個鍵呼叫時,輸出將有與key1的元素的屬性對應的鍵inp。在上面的示例中,如果我們呼叫collect(inp, "a", ...keyRest),則輸出將包含鍵x和y。對于key,我們將其屬性為x的元素收集到另一個陣列中,然后key處的值為。和鑰匙類似。也就是說,我們將輸入陣列拆分為對應于鍵值的子陣列,然后對每個子陣列進行評估。inpa"x"inpXxcollect(inpX, ...keyRest)ykey1collect(subArr, ...keyRest)
這是演算法的口頭描述。讓我們看看它對 for 的型別意味著什么collect():
declare function collect<K extends (keyof T)[], T extends object>(
arr: (T & Record<K[number], string>)[], ...keys: K): Collect<K>;
type Collect<K extends PropertyKey[]> =
K extends [any] ? string[] :
K extends [any, ...infer R extends PropertyKey[]] ? { [k: string]: Collect<R> } :
never;
這里我們說這collect()是一個通用函式,它接受物件型別的元素陣列和元組型別T的鍵串列。我們進行約束,以便陣列的每個元素都是型別的,并且在元組中的每個鍵元素處都有一個屬性。我們進行約束,使每個關鍵元素都是 的某個關鍵。 K arrarrTstringKKT
我們回傳一個 type 的值Collect<K>,其中Collect<K>本身是一個遞回條件型別,表示具有嵌套string 索引簽名且其基本情況值型別為的物件string[]。
現在開始實施:
function collect(arr: any[], ...keys: string[]) {
if (!keys.length) throw new Error("need at least one key");
const [k, ...rest] = keys;
// base case
if (!rest.length) return arr.map(v => v[k]);
// recurse; first collect the sub-arrays for each value at key k
const subArrays: Record<string, any[]> = {}
arr.forEach(v => (subArrays[v[k]] ??= []).push(v));
// then build the return object by calling collect(subArrayVk, ...rest) for each subarray
const ret: Record<string, any> = {};
Object.keys(subArrays).forEach(vk => ret[vk] = collect(subArrays[vk], ...rest));
return ret;
}
因為函式的呼叫簽名回傳通用條件型別,所以最容易使函式成為單呼叫簽名多載,以便松散地檢查實作。這只是意味著我們在實作之前有一個宣告的呼叫簽名:
// call signature
function collect<K extends (keyof T)[], T extends object>(
arr: (T & Record<K[number], string>)[], ...keys: K): Collect<K>;
// implementation
function collect(arr: any[], ...keys: string[]) {
// ? snip, see above
}
好吧,讓我們測驗一下:
const outp = collect(inp, "a", "b", "c");
console.log(outp);
// {x:{u: ["q","s"], v:["r","t"]}, y:{u:["q","r"], v:["s"]}}
這樣可行!你的例子:
const x = collect(arr, "make", "classification", "segment", "model", "catalogDetail");
console.log(x);
/* {
"Acura": {
"Mid SUV": {
"Competitive Trucks": {
"RDX": [
"RDX_SUV_4_Gasoline_2013_Base w/Tech_FWD_3.5_6_105.7_Automatic"
]
}
},
"Midsize Car": {
"Competitive Cars": {
"TSX": [
"TSX_Sedan_4_Gasoline_2012_Base w/Tech_FWD_2.4_4_106.4_Automatic"
]
}
}
},
"Aston Martin": {
"Compact Car": {
"Competitive Cars": {
"DB11": [
"DB11_Convertible_2_Gasoline_2019_Volante_RWD_4.0_8_110.4_Automatic"
]
}
}
}
} */
那也行!
游樂場代碼鏈接
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/537237.html
上一篇:如何在typeScript中使用模板文字連接兩個字串?
下一篇:Angular2選擇表單不捕獲值
