基于另一个数组的es6过滤器数组没有变异

es6 filter array based on another array with out mutating

过滤数组在这里被问了很多,但是 none 我找到的问题和答案考虑了我需要的 2 个条件:
1. 不改变对象。
2. 使用es6(ecmascript2015)及以上版本
3. 获取一个新数组,其中包含覆盖的对象和值。

我的问题的一部分实际上有一个答案,那就是如何过滤,但感觉像是一个 hack 而不是真正的解决方案,第二部分是如何获得完整的原始数组以及从第二个数组,但不改变对象。

这是我的代码,如您所见,我正在显式分配 {dirty:true} 而不是从数组中传递对象本身:

    const docPositions = [
    {
      active : false,
      dirty : false,
      key : "somekey2"
    },
    {
      active : false,
      dirty : false,
      key : "somekey1"
    },
    {
      active : false,
      dirty : false,
      key : "somekey4"
    },
    {
      active : false,
      dirty : false,
      key : "somekey3"
    }
  ]
const dirtyPositions = [
  {
      active : false,
      dirty : true,
      key : "somekey1"
  },
    {
      active : false,
      dirty : true,
      key : "somekey3"
  } 
]

let result = docPositions.filter(x=> dirtyPositions.some(y=>y.key == x.key))
                         .map(o=> Object.assign({},o,{dirty:true}));

console.log(result);

结果:

Array [
  Object {
    "active": false,
    "dirty": true,
    "key": "somekey1"
  },
  Object {
    "active": false,
    "dirty": true,
    "key": "somekey3"
  }
]

期望的结果:

 Array   [
    {
      active : false,
      dirty : false,
      key : "somekey2"
    },
    {
      active : false,
      dirty : true,
      key : "somekey1"
    },
    {
      active : false,
      dirty : false,
      key : "somekey4"
    },
    {
      active : false,
      dirty : true,
      key : "somekey3"
    }
  ]

您可以通过在脏位置上使用 find 来实现,returns undefined 或脏对象。如果你把它作为 Object.assign 的第三个参数和匹配的 docPosition 放在第二个位置,你会得到想要的结果:

const result = docPositions.map(
    x => Object.assign({}, x, dirtyPositions.find(y=>y.key == x.key)));

const docPositions = [
    {
      active : false,
      dirty : false,
      key : "somekey2"
    },
    {
      active : false,
      dirty : false,
      key : "somekey1"
    },
    {
      active : false,
      dirty : false,
      key : "somekey4"
    },
    {
      active : false,
      dirty : false,
      key : "somekey3"
    }
  ]
const dirtyPositions = [
  {
      active : false,
      dirty : true,
      key : "somekey1"
  },
    {
      active : false,
      dirty : true,
      key : "somekey3"
  } 
]

const result = docPositions.map(
    x => Object.assign({}, x, dirtyPositions.find(y=>y.key == x.key)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

对于大型数组...

上面的时间复杂度为O(n²),所以当两个数组都很大时,在每个.map()迭代中执行.find()可能变得太昂贵了。在这种情况下,最好先将 dirtyPositions 数组转换为 Map。为了保持 函数式编程 风格,您可以将该 Map 作为上下文传递给 .map(),这样它就可以作为 this 使用。为此,您需要使用标准的 function 表示法:

const result = docPositions.map(function (x) { 
    return Object.assign({}, x, this.get(x.key));
}, new Map(dirtyPositions.map(y=>[y.key, y])));

这将 运行 O(n),因为 get() 操作在大多数实现中 near-constant 及时。

const docPositions = [
    {
      active : false,
      dirty : false,
      key : "somekey2"
    },
    {
      active : false,
      dirty : false,
      key : "somekey1"
    },
    {
      active : false,
      dirty : false,
      key : "somekey4"
    },
    {
      active : false,
      dirty : false,
      key : "somekey3"
    }
  ]
const dirtyPositions = [
  {
      active : false,
      dirty : true,
      key : "somekey1"
  },
    {
      active : false,
      dirty : true,
      key : "somekey3"
  } 
]

const result = docPositions.map(function (x) { 
    return Object.assign({}, x, this.get(x.key));
}, new Map(dirtyPositions.map(y=>[y.key, y])));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

请注意,Map 构造函数可以采用 key/value 对数组(也是数组)。这个新 Map 作为可选的 thisArg 传递给 .map(),以便它可以在回调中用 this 引用。

这应该匹配为 ES6 答案

const docPositions = [
    {
      active : false,
      dirty : false,
      key : "somekey2"
    },
    {
      active : false,
      dirty : false,
      key : "somekey1"
    },
    {
      active : false,
      dirty : false,
      key : "somekey4"
    },
    {
      active : false,
      dirty : false,
      key : "somekey3"
    }
  ]
const dirtyPositions = [
  {
      active : false,
      dirty : true,
      key : "somekey1"
  },
    {
      active : false,
      dirty : true,
      key : "somekey3"
  }
  ];
  const dirtyKeys =  dirtyPositions.map(x => x.key);
    var results = docPositions.map(x => {
      let index = dirtyKeys.indexOf(x.key);
      if (index === -1) return x;
      return dirtyPositions[index];
    })
    console.log(results);