Изменение динамически вложенных массивов, зная только индексы для доступа

У меня есть необходимость изменить структуру вложенного массива объектов, которая всегда имеет один и тот же шаблон, зная только индексы для доступа к тому конкретному объекту, который я хочу изменить.

Пример массива 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, созданную динамически, для удаления определенного объекта? Есть ли лучшие способы сделать это (конечно, мой код не работает)?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
473
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вот одна версия, немного более общая, позволяющая нам динамически указывать имя 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" или что-то в этом роде). Если это ваша настоящая цель, пожалуйста, начните другой вопрос (и не стесняйтесь добавлять ссылку на него в комментариях здесь.)

Ответ принят как подходящий

Вы можете просто использовать метод 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 && match) r.splice(e, 1)
  else if (match) return match.subRows;

  return {}
}, data)

console.info(data)

Поскольку вы отметили вопрос как «рекурсия», вот простая рекурсия:

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.info(f(data, path));

Вот итеративное решение с использованием объектного сканирования

Сначала создаем путь, затем склеиваем найденную сущность

// 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.info(prune(myData, [0, 1, 0])); // returns true iff deleted
// => true

console.info(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/[email protected]"></script>

Отказ от ответственности: я автор object-scan

Другие вопросы по теме