【问题标题】:Converting nested array to object, matching array index with object id将嵌套数组转换为对象,将数组索引与对象 id 匹配
【发布时间】:2019-01-19 16:31:32
【问题描述】:

我目前正在努力使用 redux 减速器。

//backend response
const response = {
    data: {
        results: {
            222: {
                items: ['id1', 'id3']
            },
            333: {
                items: ['id2', 'id4', 'id999 (UNKNOWN)']
            }
        }
    }
};

//currently saved in redux state
const stateItems = [
    {
        id: 'id1',
        name: 'item ONE'
    }, {
        id: 'id2',
        name: 'item TWO'
    }, {
        id: 'id3',
        name: 'item THREE'
    }, {
        id: 'id4',
        name: 'item FOUR'
    }, {
        id: 'id5',
        name: 'item FIVE (UNUSED)'
    }, {
        id: 'id6',
        name: 'item SIX (UNUSED)'
    }
];


//converting items: ['ids'] => items: [{id: 'id', name: 'itemName'}]
const result = Object.values(response.data.results).map((keys, index, array) => {
    keys.items = keys.items.map(itemId => {
        return stateItems[stateItems.findIndex(x => x.id === itemId)];
    });

    return response.data.results;
});


//final result should be:
const expectedFinalResult = {
    222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
    333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};

//both should be equal:
console.log(JSON.stringify(expectedFinalResult));
console.log(JSON.stringify(result));
console.log('same result: ' + JSON.stringify(result) === JSON.stringify(expectedFinalResult));

我没有想法,如何实现它。 UNUSEDUNKNOWN 也应该被过滤掉。所以这个例子中的最终结果就像const expectedFinalResult一样。目前const result返回一个错误的结果。

希望有人有更好的想法或更好的方法。

谢谢

【问题讨论】:

  • 请使用 Stack Snippets 来获取可运行的示例,而不是使用场外资源。使用[<>] 工具栏按钮打开片段编辑器; here's how to do one。由于您在问题中包含了所有相关代码(很好!)我已经为您将其复制到一个 sn-p 中。
  • 注意:JSON.stringify(result) === JSON.stringify(expectedFinalResult)不是比较两个对象图的可靠方法。例如,JSON.stringify({a: 1, b: 2}) === JSON.stringify({b: 2, a: 1})false(根据规范)。
  • 在这个问题上展示你的努力做得很好!

标签: javascript node.js reactjs redux


【解决方案1】:

Object.entries 让您走在正确的轨道上。您可以使用解构来选择键 ('222', '333') 和值对象的 items 数组,然后使用该数组过滤 stateItems 并为结果中的每个条目生成 items 数组:

const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
    result[key] = {
        items: stateItems.filter(item => items.includes(item.id))
    };
}

现场示例:

//backend response
const response = {
    data: {
        results: {
            222: {
                items: ['id1', 'id3']
            },
            333: {
                items: ['id2', 'id4', 'id999 (UNKNOWN)']
            }
        }
    }
};

//currently saved in redux state
const stateItems = [
    {
        id: 'id1',
        name: 'item ONE'
    }, {
        id: 'id2',
        name: 'item TWO'
    }, {
        id: 'id3',
        name: 'item THREE'
    }, {
        id: 'id4',
        name: 'item FOUR'
    }, {
        id: 'id5',
        name: 'item FIVE (UNUSED)'
    }, {
        id: 'id6',
        name: 'item SIX (UNUSED)'
    }
];


const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
    result[key] = {
        items: stateItems.filter(item => items.includes(item.id))
    };
}

//final result should be:
const expectedFinalResult = {
    222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
    333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};

//both should be equal:
console.log(JSON.stringify(result, null, 4));
.as-console-wrapper {
  max-height: 100% !important;
}

这使得多次通过stateItems。如果它或response.data.results 真的、真的、真的、真的很大(比如几十万),那么可能值得做一个MapstateItems 的id 代替:

// Create map of state items (only once each time stateItems changes):
const stateItemMap = new Map(stateItems.map(item => [item.id, item]));

// Map results (each time you get results):
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
    result[key] = {
        items: items.map(id => stateItemMap.get(id))
    };
}

现场示例:

//backend response
const response = {
    data: {
        results: {
            222: {
                items: ['id1', 'id3']
            },
            333: {
                items: ['id2', 'id4', 'id999 (UNKNOWN)']
            }
        }
    }
};

//currently saved in redux state
const stateItems = [
    {
        id: 'id1',
        name: 'item ONE'
    }, {
        id: 'id2',
        name: 'item TWO'
    }, {
        id: 'id3',
        name: 'item THREE'
    }, {
        id: 'id4',
        name: 'item FOUR'
    }, {
        id: 'id5',
        name: 'item FIVE (UNUSED)'
    }, {
        id: 'id6',
        name: 'item SIX (UNUSED)'
    }
];

// Create map of state items (only once each time stateItems changes):
const stateItemMap = new Map(stateItems.map(item => [item.id, item]));

// Map results (each time you get results):
const result = {};
for (const [key, {items}] of Object.entries(response.data.results)) {
    result[key] = {
        items: items.map(id => stateItemMap.get(id))
    };
}

//final result should be:
const expectedFinalResult = {
    222: {items: [{id: 'id1', name: 'item ONE'}, {id: 'id3', name: 'item THREE'}]},
    333: {items: [{id: 'id2', name: 'item TWO'}, {id: 'id4', name: 'item FOUR'}]}
};

//both should be equal:
console.log(JSON.stringify(result, null, 4));
.as-console-wrapper {
  max-height: 100% !important;
}

【讨论】:

  • 哇,感谢并感谢以前的提示。我之前用.entries 尝试过,但我认为这是错误的方向,我没有尝试使用for循环。阵列不会很大。主要是 1-100 个项目。非常感谢。
【解决方案2】:

你可以用 reduce 来做到这一点:

Object.entries(response.data.results)
    .reduce((acc, [key, { items }]) => ({
        ...acc,
        [key]: { // we can use the dynamic keys to add in our accumulated object
            items: items
                .map(itemId => stateItems.find(x => x.id === itemId)) // you can use find directly instead of findIndex then access
                .filter(Boolean) // we skip the unneeded elements
        }
    }), {});

【讨论】:

    猜你喜欢
    • 2021-07-27
    • 1970-01-01
    • 2019-04-26
    • 1970-01-01
    • 2018-01-04
    • 2015-03-26
    • 2019-01-31
    相关资源
    最近更新 更多