如何通过(lodash)路径表达式以不可变的方式从(嵌套)数组中删除元素?

时间:2018-02-06 13:40:06

标签: javascript lodash

我试图通过路径表达式以不可变的方式从对象中的数组中删除元素/同时保留原始对象并只更改路径上更改的对象。

所以我尝试使用一些方法:

const doc = {a: ['a', 'b']};
const newDoc = removeAt('a[0]', doc);

执行后,newDoc是{a:[' b']};和doc保持不变。

我尝试使用lodash取得了一些成功,但它真的很糟糕我需要如何设置它。有谁知道如何删除'没有所有这些中间步骤的那个元素?



function removeAt(path, obj) {
  const arrayPath = _.initial(_.toPath(path));
  const arrayIndex = _.last(_.toPath(path));
  const [array] = _.at(obj, [arrayPath]);
  const newArray = _.concat(_.slice(array, 0, arrayIndex), _.slice(array, arrayIndex + 1));
  const newObj = _.setWith(_.clone(obj), arrayPath, newArray, _.clone);
  return newObj;
}

const doc = {
  'stringList': ['a', 'b'],
  'container': {
    objectList: [{
      a: 'a',
      b: 'b'
    }, {
      c: 'c',
      d: 'd'
    }]
  }
};
const path = 'container.objectList.[0]';
const newDoc = removeAt(path, doc);

console.log('old doc and new newDoc:', {
  doc,
  newDoc
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>
&#13;
&#13;
&#13;

我的removeAt工作(并保持stringList包含相同的对象),但是复杂的方式..: - /我正在寻找一种更清晰的方法来删除这些内容。最可爱的是lodash,lodash fp或普通JS ;-)

使用不可变的方式,我的意思是我需要在源对象中进行任何更改,但是生成一个新的Object,其中删除条目的路径上的那些对象确实已更改。这样我就有尽可能少的新对象。我需要做出反应,以便快速检查是否有任何变化,以及是否需要重新绘制其中一部分的UI树,这应该简化为更改的部分。

3 个答案:

答案 0 :(得分:0)

您可以尝试将lodash.removelodash.set

一起使用

在您的情况下,您可以尝试执行类似

的操作
const doc = {a: ['a', 'b']};
const newDoc = _.set(doc, 'a', _.remove(doc.a, (v,i) => i !== 0 ));

答案 1 :(得分:0)

我不知道lodash,但它显然有一个内置的get(obj, path)。 因此,如果您只是从数组中删除元素,则以下将获取该数组,然后通过其索引删除元素(不进行检查)。所有这些都没有改变源对象。

const doc = {
  'stringList': ['a', 'b'],
  'container': {
    objectList: [{
      a: 'a',
      b: 'b'
    }, {
      c: 'c',
      d: 'd'
    }]
  }
};

function removeElement(obj, pathToArr, index){
  // I don't know of a better way to clone, according to flob, this doesn't play well with React
  //const clone = JSON.parse(JSON.stringify(obj));
  const clone = _.clone(obj);
  const arr = _.get(clone, pathToArr);
  arr.splice(index, 1);
  return clone;
}

console.log(removeElement(doc, "container.objectList", 0));

答案 2 :(得分:0)

我会使用:

重写你的函数

_.cloneDeep不要改变原始对象

_.unset通过路径表达式

来自对象内数组的元素

_.set新的_.compact ed数组

function removeAt(path, index, obj) {
  var res = _.cloneDeep(obj);
  _.unset(res, path+'['+index+']');
  _.set(res, path, _.compact(_.get(res, path)));

  return res;
}

const doc = {
  'stringList': ['a', 'b'],
  'container': {
    objectList: [{
      a: 'a',
      b: 'b'
    }, {
      c: 'c',
      d: 'd'
    }]
  }
};
const path = 'container.objectList';
const newDoc = removeAt(path, 0,  doc);

console.log(doc, newDoc);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>