#javascript #arrays #json #recursion #ecmascript-6
#javascript #массивы #json #рекурсия #ecmascript-6
Вопрос:
У меня есть необходимость изменить структуру вложенного объекта-массива, которая всегда имеет один и тот же шаблон, зная только индексы для доступа к этому конкретному объекту, который я хочу изменить.
Пример массива JSON:
[
{
"name":"bob",
"age":5,
"subRows":[
{
"name":"paul",
"age":10,
"subRows":[]
},
{
"name":"claire",
"age":20,
"subRows":[
{
"name":"carl",
"age":40,
"subRows":[]
}
]
}
}
]
Мне нужно динамически удалять объект, который может быть разным каждый раз, скажем, с именем «carl», поэтому для достижения этого ожидаемого результата:
[
{
"name":"bob",
"age":5,
"subRows":[
{
"name":"paul",
"age":10,
"subRows":[]
},
{
"name":"claire",
"age":20,
"subRows":[]
}
}
]
Знание всех индексов структуры Json для доступа к ней:
let indexesArray = [0, 1, 0];
Я пробовал это:
const deleteObject = (jsonData, indexesArray) =>{
let pathToDelete = "jsonData[indexesArray[0]]";
for(let i=1; i<indexesArray.length(); i ){
pathToDelete = ".subRows["i"]";
]
pathToDelete = []; //empty the array removing "carl" object
return jsonData;
}
Как я могу заставить javascript обрабатывать мою переменную pathTodelete, созданную динамически, для удаления определенного объекта? Есть ли лучшие способы сделать это (конечно, мой код не работает)?
Ответ №1:
Вы могли бы просто использовать reduce
метод для массива индексов, и когда будет найден его последний индекс и совпадение, вы можете удалить этот элемент из массива с помощью индекса, используя splice
метод.
const data = [{"name":"bob","age":5,"subRows":[{"name":"paul","age":10,"subRows":[]},{"name":"claire","age":20,"subRows":[{"name":"carl","age":40,"subRows":[]}]}]}]
let indexesArray = [0, 1, 0];
indexesArray.reduce((r, e, i, a) => {
const match = r[e];
if (a.length == i 1 amp;amp; match) r.splice(e, 1)
else if (match) return match.subRows;
return {}
}, data)
console.log(data)
Ответ №2:
Вот одна из версий, немного более общая, позволяющая нам subRow
динамически указывать имя для генерации функции, которая это делает:
const removeIndexPath = (subName) => (xs, [i, ...is]) =>
i === undefined
? xs
: is.length === 0
? [... xs .slice (0, i), ... xs .slice (i 1)] // skip xs[i]
: [
... xs .slice (0, i),
... (i in xs // replace xs[i] by recurring with the remaining path on subName
? [{...xs[i], [subName]: removeIndexPath (subName) (xs [i] [subName] || [], is)}]
: [] // handle missing nodes
),
... xs .slice (i 1)
]
const removeSubRowPath = removeIndexPath ('subRows')
const input = [{name: "bob", age: 5, subRows: [{name: "paul", age: 10, subRows: []}, {name: "claire", age: 20, subRows: [{name: "carl", age: 40, subRows: []}]}]}]
console .log ('without carl:', removeSubRowPath (input, [0, 1, 0]))
console .log ('without clair:', removeSubRowPath (input, [0, 1]))
console .log ('without paul:', removeSubRowPath (input, [0, 0]))
console .log ('without bob:', removeSubRowPath (input, [0]))
console .log ('without nonexistent node:', removeSubRowPath (input, [0, 3, 5]))
.as-console-wrapper {max-height: 100% !important; top: 0}
Он обрабатывает узлы, которые не имеют subRow
(или любого другого) свойства, и обрабатывает попытки удаления несуществующих индексов в любом месте пути, просто возвращая копию оригинала.
Мне интересно, является ли это основной целью. Если это шаг, предпринятый после первого нахождения пути к «carl», вам может быть лучше написать специальную функцию, которая удаляет вложенный узел, соответствующий предоставленному предикату (возможно ({name}) => name == "carl"
, или что-то подобное).) Если это ваша реальная цель, пожалуйста, задайте другой вопрос (и не стесняйтесь добавлять ссылку на него в комментариях здесь.)
Ответ №3:
Поскольку вы отметили вопрос «рекурсия», вот простая рекурсия:
function f(arr, path){
function g(i, curr){
if (i == path.length - 1){
curr.subRows.splice(path[i], 1);
return arr;
} else {
return g(i 1, curr.subRows[path[i]]);
}
}
return g(1, arr[path[0]]);
}
var data = [{"name":"bob","age":5,"subRows":[{"name":"paul","age":10,"subRows":[]},{"name":"claire","age":20,"subRows":[{"name":"carl","age":40,"subRows":[]}]}]}];
var path = [0, 1, 0];
console.log(f(data, path));
Ответ №4:
Вот итеративное решение с использованием object-scan
Сначала мы создаем путь, затем мы объединяем найденный объект
// const objectScan = require('object-scan');
const myData = [{ name: 'bob', age: 5, subRows: [ { name: 'paul', age: 10, subRows: [] }, { name: 'claire', age: 20, subRows: [{ name: 'carl', age: 40, subRows: [] }] } ] }];
const prune = (data, indices) => objectScan(
[indices.map((e) => `[${e}]`).join('.subRows')],
{
rtn: 'bool',
abort: true,
filterFn: ({ property, parent }) => parent.splice(property, 1)
}
)(data);
console.log(prune(myData, [0, 1, 0])); // returns true iff deleted
// => true
console.log(myData);
// => [ { name: 'bob', age: 5, subRows: [ { name: 'paul', age: 10, subRows: [] }, { name: 'claire', age: 20, subRows: [] } ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>
Отказ от ответственности: я автор object-scan