【问题标题】:es6 filter array based on another array with out mutating基于另一个数组的 es6 过滤器数组,没有变异
【发布时间】:2017-01-21 08:35:29
【问题描述】:

过滤数组在这里被问了很多,但我发现的问题和答案都没有考虑到我需要的两个条件:
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"
    }
  ]

【问题讨论】:

  • 您最后列出的输出不是代码产生的。您可能没有从实际输出中复制它。提示:dirty 在输出中应该是true,而active 不应该。
  • 如果您想将 dirty 设置为 true,我认为您无法避免额外的映射。

标签: javascript arrays ecmascript-6 immutability


【解决方案1】:

您可以通过在脏位置上使用find 来做到这一点,它返回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() 操作在时间上几乎是恒定的。

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 构造函数可以采用键/值对数组(也是数组)。这个新的 Map 作为可选的thisArg 传递给.map(),以便可以在回调中使用this 对其进行引用。

【讨论】:

  • 我的错误,问题不清楚。我希望现在很清楚(不过感谢您的帮助)。
  • 好的,所以我交换了您示例中的数组以获得所需的结果:const result = docPositions.map(x => Object.assign({}, x,dirtyPositions.find(y=>y.key == x.key))); 和第二个示例:const result = docPositions.map(function (x) { return Object.assign({}, x,this.get(x.key)); }, new Map(dirtyPositions.map(x=>[x.key, x])));
  • 谢谢伙计,虽然我仍在尝试找出第二个更有效示例的语法和逻辑:)
  • 我在最后加了一点解释。如果您还有其他需要澄清的地方,请告诉我。
  • 嗯,map 没有强引用,以后会不会出现内存泄漏?
【解决方案2】:

这应该与 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    • 1970-01-01
    • 1970-01-01
    • 2018-04-04
    相关资源
    最近更新 更多