#javascript #node.js #json #functional-programming
#javascript #node.js #json #функциональное программирование
Вопрос:
Учитывая следующие два объекта json, где files
представляет собой массив каталогов и colourCodes
представляет отображение из цвета в status
, я хочу обработать массив файлов (который на самом деле является списком каталогов), чтобы определить структуру каталогов. В каждом file
folderColorRgb
из них отображается статус (статус можно посмотреть из colourCodes
константы — если цвет не существует, colourCodes
тогда статус есть Not covered
).
const colourCodes = {
'#4986e7': 'Covered 100%',
'#f83a22': 'Covered - weak',
}
const files = [
{
id: '1nn7_JlbwQCxyz7qecqEtbWvY4C9Q2S3M',
name: 'cell biology',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
},
{
id: '1bcNxav7kq--E1Qabu3tcXk9DxvRdCcgR',
name: 'ecology',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
folderColorRgb: '#4986e7'
},
{
id: '1MmkaP5xveClf6BfrhjHyYv4Q_Vaq1vf_',
name: 'infection and response',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
folderColorRgb: '#8f8f8f'
},
{
id: '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR',
name: 'biology',
parents: [ '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2' ],
folderColorRgb: '#16a765'
},
{
id: '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2',
name: 'science',
parents: [ '0AF24wY_V36dlUk9PVA' ],
folderColorRgb: '#a47ae2'
},
{
id: 'physics-id',
name: 'physics',
parents: [ '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2' ],
folderColorRgb: '#16a765'
},
{
id: 'electricity-id',
name: 'electricity',
parents: [ 'physics-id' ],
folderColorRgb: '#f83a22'
},
]
Результат, которого я хочу достичь, заключается в следующем:
{
science: {
biology: {
'cell biology': { status: 'Not covered' },
ecology: { status: 'Covered 100%' },
'infection and response': { status: 'Not covered' },
},
physics: { electricity: { status: 'Covered - weak' } },
},
}
Таким образом, это структура папок files
массива, представленного в JSON. Вы можете сделать следующие предположения
parents
Массив каждого файла всегда будет содержать одинparentId
, то есть ссылку на родительскую папку.- Все
parentId's
они существуют как aid
в файловом массиве — за исключением каталога верхнего уровня (например, science в этом случае родительский идентификатор для science не существуетfiles
.
Кто-нибудь знает хороший способ добиться этого?
Ответ №1:
Я думаю, что это помогает сначала преобразовать ваш ввод в формат, в котором есть только то, что вам нужно:
const Node = ({ id, name, parents: [parentId], folderColorRgb }) => ({
id,
name,
parentId,
status: colourCodes[folderColorRgb] || null,
children: []
});
Теперь проще написать функцию, которая выводит нужный формат:
Node.toObj = node => ({
[node.name]: node.children.length
? Object.assign(...node.children.map(Node.toObj))
: { status: node.status || "Not covered" }
});
Теперь задача состоит в том, чтобы:
- Свяжите дочерние элементы с их родительскими
- Найдите корневой узел
Я выбрал создание индекса { nodeId: node }
и одного forEach
, который создает ссылки и сохраняет корневой узел:
const foldersById = Object.fromEntries(
files
.map(Node)
.map(f => [f.id, f])
);
// Note: this mutates the nodes
let root = null;
Object
.values(foldersById)
.forEach(f => {
const parent = foldersById[f.parentId];
if (parent) parent.children.push(f);
else root = f;
});
Затем вы выводите результат путем вызова Node.toObj(root)
.
Полный код в выполняемом фрагменте:
const colourCodes = {
'#4986e7': 'Covered 100%',
'#f83a22': 'Covered - weak',
}
const files = [{
id: '1nn7_JlbwQCxyz7qecqEtbWvY4C9Q2S3M',
name: 'cell biology',
parents: ['1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR'],
},
{
id: '1bcNxav7kq--E1Qabu3tcXk9DxvRdCcgR',
name: 'ecology',
parents: ['1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR'],
folderColorRgb: '#4986e7'
},
{
id: '1MmkaP5xveClf6BfrhjHyYv4Q_Vaq1vf_',
name: 'infection and response',
parents: ['1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR'],
folderColorRgb: '#8f8f8f'
},
{
id: '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR',
name: 'biology',
parents: ['1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2'],
folderColorRgb: '#16a765'
},
{
id: '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2',
name: 'science',
parents: ['0AF24wY_V36dlUk9PVA'],
folderColorRgb: '#a47ae2'
},
{
id: 'physics-id',
name: 'physics',
parents: ['1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2'],
folderColorRgb: '#16a765'
},
{
id: 'electricity-id',
name: 'electricity',
parents: ['physics-id'],
folderColorRgb: '#f83a22'
},
]
const Node = ({
id,
name,
parents: [parentId],
folderColorRgb
}) => ({
id,
name,
parentId,
status: colourCodes[folderColorRgb] || null,
children: []
});
Node.toObj = node => ({
[node.name]: node.children.length ?
Object.assign(...node.children.map(Node.toObj)) :
{ status: node.status || "Not covered" }
});
const foldersById = Object.fromEntries(
files
.map(Node)
.map(f => [f.id, f])
);
// Note: this mutates the nodes
let root = null;
Object
.values(foldersById)
.forEach(f => {
const parent = foldersById[f.parentId];
if (parent) parent.children.push(f);
else root = f;
});
console.log(Node.toObj(root));
.as-console-wrapper {
min-height: 100%;
}
Комментарии:
1. Спасибо @user3297291, это очень удобное решение. Я собираюсь принять ответ в среду .. на данный момент у вас определенно есть лучшее решение.
Ответ №2:
Я придумал следующее решение, но не приму свой собственный ответ и оставлю вопрос открытым, чтобы посмотреть, есть ли у кого-нибудь более элегантный способ сделать это
const colourCodes = {
'#4986e7': 'Covered 100%',
'#f83a22': 'Covered - weak',
}
const files = [
{
id: '1nn7_JlbwQCxyz7qecqEtbWvY4C9Q2S3M',
name: 'cell biology',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
},
{
id: '1bcNxav7kq--E1Qabu3tcXk9DxvRdCcgR',
name: 'ecology',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
folderColorRgb: '#4986e7'
},
{
id: '1MmkaP5xveClf6BfrhjHyYv4Q_Vaq1vf_',
name: 'infection and response',
parents: [ '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR' ],
folderColorRgb: '#8f8f8f'
},
{
id: '1YewXh1WkIVIxOuHTV9acYG7WDE55EnPR',
name: 'biology',
parents: [ '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2' ],
folderColorRgb: '#16a765'
},
{
id: '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2',
name: 'science',
parents: [ '0AF24wY_V36dlUk9PVA' ],
folderColorRgb: '#a47ae2'
},
{
id: 'physics-id',
name: 'physics',
parents: [ '1WVm7S1fw8Neg7FM80QNxcMWvVc_w_Jt2' ],
folderColorRgb: '#16a765'
},
{
id: 'electricity-id',
name: 'electricity',
parents: [ 'physics-id' ],
folderColorRgb: '#f83a22'
},
]
function getStatus(folder) {
return colourCodes[folder.folderColorRgb] || 'Not covered'
}
function extractFolderStructure(parentFolder) {
const children = files.filter(f => f.parents.includes(parentFolder.id))
if (children.length==0) {
const status = getStatus(parentFolder)
return {[parentFolder.name]: {status}}
}
const childObjects = children.map(c => {
const returnObj = extractFolderStructure(c)
return returnObj
})
const fullObj = {[parentFolder.name] : {}}
childObjects.forEach(co => {
fullObj[parentFolder.name][Object.keys(co)[0]] = co[Object.keys(co)[0]]
})
return fullObj
}
console.log(extractFolderStructure(files.find(f => f.name === 'science')))