簡體   English   中英

JS:如何過濾對象數組,在第一個 object 中添加一個鍵,其值為過濾元素的 rest?

[英]JS: How to filter an array of objects, add to the first object a key with values of the rest of filtered elements?

我正在嘗試在 Tabulator JS 中實現用戶從表中重建具有樹結構的新表的機會。 所以 tableData 是一個假定的表,而 columnTree 是用戶的選擇,哪一列必須是樹根。

我的想法是首先將唯一的鍵值存儲在一個數組中,然后遍歷 tableData 按每個鍵對其進行過濾,將過濾對象的 rest 的值添加到第一個元素 [_children] 鍵。

var columnTree = "continent";

var tableData = [
                {continent:"Asia", country:"China"},
                {continent:"Asia", country:"Vietnam"},
                {continent:"Asia", country:"Thai"},
                {continent:"America", country:"USA"},
                {continent:"America", country:"Canada"},
                {continent:"Africa", country:"Egypt"},
                {continent:"Africa", country:"Somalia"},
            ];

獲取唯一鍵

var unique = tableDataNested.map(item => item[columnTree]).filter((value, index, self) => self.indexOf(value) === index);

// ["Asia", "America", "Afrika"]

過濾器 function

function filterByValue(array, string) {
                return array.filter(o =>
                    Object.keys(o).some(k => o[k].toLowerCase().includes(string.toLowerCase())));
            };

最后一步

var finalArray = [];
unique.forEach(function(continent) {
                //temporary array with values of each continent 
                var tempArray = filterByValue(tableDataNested, continent);
                console.log(tempArray);
                //get the first object
                console.log(tempArray[0]);
                //add to the first object '_children' key with values of the rest of objects except the 
                //first.
                var finalResult = tempArray[0]['_children'] = [tempArray.slice(1)];
                console.log(finalResult);
                finalArray.push(finalResult);
            });

問題是,它在第二大陸墜毀,我不明白為什么

VM480:3 Uncaught TypeError: o[k].toLowerCase is not a function
    at <anonymous>:3:51
    at Array.some (<anonymous>)
    at <anonymous>:3:36
    at Array.filter (<anonymous>)
    at filterByValue (<anonymous>:2:30)
    at <anonymous>:2:33
    at Array.forEach (<anonymous>)
    at <anonymous>:1:8

我的理想結果是

var finalArray = [
                {continent:"Asia", country:"China", "_children": [
                    {continent:"Asia", country:"Vietnam"},
                    {continent:"Asia", country:"Thai"}
                ]},
                {continent:"America", country:"USA", "_children": [
                    {continent:"America", country:"Canada"},
                ]},
                {continent:"Africa", country:"Egypt",  "_children": [
                    {continent:"Africa", country:"Somalia"}
                ]}
            ];

例如,您最好使用通用groupBy

function groupBy(ary, fn) {
    let m = new Map();
    for (let x of ary) {
        let key = fn(x);
        if (!m.has(key))
            m.set(key, []);
        m.get(key).push(x);
    }
    return m;
}

接着

let groupMap = groupBy(tableData, x => x[columnTree]);
let result = [];

for (let [first, ...rest] of groupMap.values()) {
    first._children = rest;
    result.push(first);
}

請注意,這也會改變原始tableData數組,如果不希望這樣做,請將循環體更改為:

result.push({...first, _children: rest});

更簡單的方法是使用.reduce來聚合您的數據。

reduce()方法對數組的每個元素執行一個化簡器 function(您提供),從而產生一個 output 值。

 var tableData = [ {continent:"Asia", country:"China"}, {continent:"Asia", country:"Vietnam"}, {continent:"Asia", country:"Thai"}, {continent:"America", country:"USA"}, {continent:"America", country:"Canada"}, {continent:"Africa", country:"Egypt"}, {continent:"Africa", country:"Somalia"}, ]; var result = tableData.reduce((acc, item) => { if(acc[item.continent] === undefined) acc[item.continent] = { continent: item.continent, country: item.country, _children: []} else acc[item.continent]._children.push(item); return acc; }, {}); console.log(Object.values(result));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM