Удалить совпавший объект из глубоко вложенного массива объектов

== выполняет контрольную проверку равенства, ссылаясь на то, что 2 объекта (строки в этом случае) относятся к одному и тому же объекту в памяти.

Метод equals() будет проверять, будет ли содержимое или состояния двух объектов одинаковы.

Очевидно, что == работает быстрее, но во многих случаях может (может) давать ложные результаты, если вы просто хотите сказать, имеет ли 2 String s тот же текст.

Определенно рекомендуется использовать метод equals().

Не беспокойтесь о производительности. Некоторые способы поощрения использования String.equals():

  1. Реализация String.equals() сначала проверяет ссылочное равенство (используя ==), и если две строки одинаковы по ссылке, дальнейший расчет Выполняется!
  2. Если 2 ссылки на строки не совпадают, String.equals() будет проверять длину строк. Это также является быстрой операцией, поскольку класс String хранит длину строки, не нужно считать символы или кодовые точки. Если длины отличаются, дальнейшая проверка не выполняется, мы знаем, что они не могут быть равными.
  3. Только если мы доберемся до этого, будет фактически сопоставлено содержимое двух строк, и это будет короткий сравнение: не все символы будут сравниваться, если мы найдем несоответствующий символ (в том же положении в 2 строках), никакие другие символы не будут проверены.

Когда все сказано и даже если у нас есть гарантия, что строки являются стажерами, использование метода equals() все еще не является издержками, которые можно было бы подумать, определенно рекомендуемым способом. Если вам нужна эффективная проверка ссылок, используйте перечисления, где гарантируется спецификацией и реализацией языка, что одно и то же значение перечисления будет одним и тем же объектом (по ссылке).

0
задан DrCord 9 March 2019 в 23:20
поделиться

4 ответа

Я построил алгоритм следующим образом:

function omitNodeWithName(tree, name) {
  if (tree.name === name) return undefined;

  const children = tree.children.map(child => omitNodeWithName(child, name))
    .filter(node => !!node);

  return {
    ...tree,
    children
  }  
}

Вы можете использовать его для возврата нового дерева без элемента:

noHydrogen = omitNodeWithName(tree, "Hydrogen")
0
ответ дан Victor Nascimento 9 March 2019 в 23:20
поделиться

Если вы не возражаете против изменения дерева параметров на месте , это должно сработать. Обратите внимание, что он вернет null, если вы попытаетесь удалить корень.

const tree = { id: 1, name: "Dog", parent_id: null, children: [ { id: 2, name: "Food", parent_id: 1, children: [] }, { id: 3, name: "Water", parent_id: 1, children: [ { id: 4, name: "Bowl", parent_id: 3, children: [] }, { id: 5, name: "Oxygen", parent_id: 3, children: [] }, { id: 6, name: "Hydrogen", parent_id: 3, children: [] } ] } ] };

const removeFromTree = (root, nameToDelete, parent, idx) => {
  if (root.name === nameToDelete) {
    if (parent) {
      parent.children.splice(idx, 1);
    }
    else return null;
  }
  
  for (const [i, e] of root.children.entries()) {
    removeFromTree(e, nameToDelete, root, i);
  }
  
  return tree;
};

console.log(removeFromTree(tree, "Oxygen"));

Ваш текущий код находится на правильном пути. Однако:

newTree = curNode.children.slice(index, index + 1);

выдвигает на первый план несколько проблем: нам нужно манипулировать массивом children родителя, чтобы удалить curNode вместо собственного children массива [116]. Я передаю родительские объекты и дочерний индекс рекурсивно через вызовы, избавляя от проблем линейной операции findIndex.

Кроме того, разрезание от index до index + 1 извлекает только один элемент и не изменяет curNode.children. Не очевидно, как использовать newArray или возвращать его через стек вызовов. splice кажется более подходящим инструментом для решения поставленной задачи: извлечение одного элемента на месте.

Обратите внимание, что эта функция удалит несколько записей, соответствующих nameToDelete.

0
ответ дан ggorlen 9 March 2019 в 23:20
поделиться

Мне нравится ответ @ VictorNascimento, но, применяя map, затем filter, каждый список children будет повторяться дважды. Вот альтернатива с reduce, чтобы избежать этого:

function removeFromTree(node, name) {
  return node.name == name
    ? undefined
    : {
        ...node,
        children: node.children.reduce(
          (children, child) => children.concat(removeFromTree (child, name) || []), [])
      }
}

В случае, если вам нужен способ удаления элементов на месте, как предложил @ggorlen, я бы порекомендовал следующее решение, которое На мой взгляд проще:

function removeFromTree(node, name) {
  if (node.name == name) {
    node = undefined
  } else {
    node.children.forEach((child, id) => {
      if (!removeFromTree(child, name)) node.children.splice(id, 1)
    })
  }
  return node
}
0
ответ дан Rodrigo Rodrigues 9 March 2019 в 23:20
поделиться

Если можно использовать Lodash + Deepdash , то:

let cleaned = _.filterDeep([tree],(item)=>item.name!='Hydrogen',{tree:true});

Вот Codepen

0
ответ дан Yuri Gor 9 March 2019 в 23:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: