用另一个数组删除/过滤对象数组 [英] Remove/Filter array of objects with another array

查看:82
本文介绍了用另一个数组删除/过滤对象数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Array.prototype.remove = function() {
  var what, a = arguments,
    L = a.length,
    ax;
  while (L && this.length) {
    what = a[--L];
    while ((ax = this.indexOf(what)) !== -1) {
      this.splice(ax, 1);
    }
  }
  return this;
};

var items = [{
  title: 'Bokningsbar',
  start: moment("2018-04-05 06:00"),
  end: moment("2018-04-05 07:00"),
  allDay: false
}, {
  title: 'Bokningsbar',
  start: moment("2018-04-05 06:00"),
  end: moment("2018-04-05 07:00"),
  allDay: false
}, {
  title: 'Bokningsbar',
  start: moment("2018-04-05 06:00"),
  end: moment("2018-04-05 07:00"),
  allDay: false
}, {
  title: 'Bokningsbar',
  start: moment("2018-04-05 06:00"),
  end: moment("2018-04-05 07:00"),
  allDay: false
}]

var datesToRemove = [{
  title: 'Bokningsbar',
  start: moment("2018-04-06 06:00"),
  end: moment("2018-04-06 07:00"),
  allDay: false
}];
console.log("Before: " + items.length)
for (var i = 0; i < datesToRemove.length; i++) {
  items.remove(moment(datesToRemove[i].start).format("YYYY-MM-DD HH:mm"));
}
console.log("After: " + items.length)

<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.0/moment.js"></script>

我想使用另一个数组作为参考从一个数组中删除对象.这两个数组仅包含下面的对象. datesToRemove 中的所有相应对象都应在 items 数组中删除.我本以为可以使用的属性是 start .不幸的是,没有 Id

I want to remove the objects from one array using another array as a reference. Both arrays only contain the object below. All the corresponding objects in datesToRemove should be removed in the items array. Properties I was thinking I could use are start. Unfortunately there is no Id

到目前为止,这是我的代码:

This is my code so far:

对象看起来像这样:

   var item = {
                            title: 'Bokningsbar',
                            start: moment(datesValue + " " + hourValue.start),
                            end: moment(datesValue + " " + hourValue.end),
                            allDay: false
                        };

Prototype.remove

Prototype.remove

       Array.prototype.remove = function () {
        var what, a = arguments,
            L = a.length,
            ax;
        while (L && this.length) {
            what = a[--L];
            while ((ax = this.indexOf(what)) !== -1) {
                this.splice(ax, 1);
            }
        }
        return this;
    };

用例:

  for (var i = 0; i < datesToRemove.length; i++) {
                            items.remove(moment(datesToRemove[i].start).format("YYYY-MM-DD HH:mm"));
                        }

使用此设置,我得到错误无法读取未定义的属性'indexOf'.并且所有的athe对象被删除.这也是一个不起作用的示例.但这也许说明了我想要的.如果有人对如何删除对象有更好的建议,请随时提出建议.

With this setup I get the error Cannot read property 'indexOf' of undefined. And all athe obects are removed. Here is also a not working example. But maybe it illustrates what I want. If anybody got a better suggestion on how to remove the objects feel free to suggest it.

非常感谢所有帮助.

推荐答案

无需扩展本机 Array 原型即可完成此任务.有一些用于处理 Array 操纵的方法,JavaScript本身已经可以使用它们,它们可以解决您的问题.此外,将自定义 Array 方法与for循环结合使用后,很容易会产生意外/意外的负面影响,从而限制了该解决方案在将来在您的应用中可扩展的程度应用.最明显的潜在陷阱是更改原始数据结构,极大地限制了可重用性,并使得难以轻松,准确地调试进一步导致应用程序堆栈下降的问题.这些本机的 Array 方法将使您的原始数据结构保持完整,在操作过程中创建 Array 实例的浅表副本,并将其作为最终结果返回.作为额外的好处,这些方法可以按您需要的多种方式和次数链接在一起.

No need to extend the native Array prototype to get this done. There are a few methods for dealing with Array manipulation that are already available natively to JavaScript and can tackle your problem. More so, following along with using a custom Array method in conjunction with a for loop for a solution could very easily produce unexpected/unintended negative side effects that limit how well this solution could scale for future use within your application. The most obvious potential pitfall is mutating your original data structures, drastically limiting reusability and making it difficult to easily and accurately debug issues caused further down the application stack. These native Array methods will keep your original data structures intact, creating shallow copies of the Array instances during manipulation and returning them as your final result. As an additional bonus, these methods can be chained together in as many ways and as many times as you may need.

  • .map()
  • .filter()
  • .reduce()

另一种常用的 Array 操作方法是 .forEach(). .forEach()方法消除了编写和维护混乱的 for 循环的麻烦;使整个代码库更易于阅读,更易于逻辑遵循.但是,与前面列出的3个 Array 操作方法不同, .forEach()不能防止更改使用的任何原始数据结构.它可以包含在您使用上述其他 Array 方法创建的链中.但是,一旦被调用, .forEach()破坏了进一步链接您的方法的能力.

Another Array manipulation method commonly utilized is .forEach(). The .forEach() method removes the hassle of having to write and maintain messy for loops; making the overall codebase much easier to read and much easier to follow logically. However, .forEach(), unlike the 3 previously listed Array manipulation methods, does NOT protect against mutating any original data structures used. It can be included in the chain you may create using the other Array methods mentioned. However, once called, .forEach() breaks the ability to chain your methods any further.

.map() .filter() .reduce()提供了一种纯函数式的迭代和操作方法 Array 的形式.尽管这3种方法仍然提供了循环遍历 Array 的方法,但是每种方法都提供了自己独特的功能和操纵目的.首先了解每种方法的不同用法对于了解何时以及如何将它们有效地链接在一起至关重要.

.map(), .filter(), and .reduce() provide a pure, functional approach to the iteration and manipulation of an Array. While all 3 methods still offer a means by which to loop over an Array, each method offers it's own unique functionality and purpose for manipulation. Understanding the distinct use of each method first is crucial to understanding when and how to chain them together effectively.

.MAP()

.MAP()

  • .map():与 .forEach()相似,此方法循环遍历给定 Array 中的每个项目.当循环遍历每个项目的索引时,将针对提供的用于操作的方法运行各个项目.最终结果是一个新的 Array ,每个项目都是循环期间提供的转换函数的乘积.使用 .map()时要记住的重要注意事项是,循环完成后返回的新 Array 始终与原始 Array 使用.当您需要返回一个新的 Array 且其项目值与原始的 Array 相比较时,这使 .map()成为一个很好的选择,它的项值可以反映所需的转换code>,以及所有项目值.
  • .map() : Similar to .forEach(), this method loops over each item in the given Array. As the loop iterates over each item's index, the individual items are run against a provided method for manipulation. The end result is a new Array with every item being the product of the transformation function provided during the loop. The important note to remember using .map() is that the new Array that is returned after the loop completes will ALWAYS be the same length as the original Array used. This makes .map() an excellent choice when you need to return a new Array with item values that reflect a desired transformation when compared against the original Array, and all of it's item values.

示例:

const originalArr = [1, 2, 3, 4, 5]

const incrementedArr = 
  originalArr.map(
    (n,i,arr) => {
      return n + 4
    }
  )

console.log(originalArr)     // console output => [1, 2, 3, 4, 5]
console.log(incrementedArr)  // console output => [5, 6, 7, 8, 9]

在上面的示例中, incrementedArr 常量可以用更简洁的方式重写.为了彻底回答您的问题,我详细地写了它,以说明要牢记的重要注意事项.默认情况下, .map() .filter() .reduce()各自提供三个参数. .map() .filter()的3个参数相同.它们是:

In the example above, the incrementedArr constant could be rewritten in a much more concise way. For the purpose of answering your question thoroughly, I wrote it verbosely to illustrate an important note to always keep in mind. .map(), .filter(), and .reduce() each offer three arguments by default. The 3 arguments for .map() and .filter() are the same. They are:

  1. 项目

在循环迭代的每个索引处找到的单个项目值

The individual item value found at each index of the loop's iteration

  • 索引

    在循环迭代期间找到的每个项目的索引值

    The index value for each item found during the iteration of the loop

  • 数组

    提供对循环所使用的原始数组的引用

    Provides a reference to the original array being used by the loop

  • 也就是说,这是上面示例中 .map()的更简洁的说明:

    That said, here's a more concise illustration of .map() from the example above:

    const originalArr = [1, 2, 3, 4, 5]
    const incrementedArr = originalArr.map(n => n + 4)
    
    console.log(originalArr)     // console output => [1, 2, 3, 4, 5]
    console.log(incrementedArr)  // console output => [5, 6, 7, 8, 9]  
    

    .FILTER()

    .FILTER()

    • .filter():同样,与 .forEach()一样,此方法循环遍历给定 Array 中的每个项目.这样做时,它会将 Array 中每个项目的值与提供的条件检查进行比较,并在以下位置为每个项目返回 true false Array 中的每个索引.最终输出将是项目的 Array ,其值全部以相同的 Boolean 返回,即为 true false 取决于提供的条件检查.这使得 .filter()成为您需要返回新的 Array 且与原始 Array 可能需要不同长度的完美选择.代码>提供.换句话说,返回的新 Array 是对条件检查的直接反映,该条件检查用于过滤原始 Array 中不再需要的项目值.
    • .filter() : Again, like .forEach(), this method loops over each item in the given Array. As it does, it compares the value of each item in the Array against a provided conditional check, returning either true or false for each item at each index within the Array. The final output will be an Array of item's whose values all returned as the same Boolean, either as true or false depending on the conditional check provided. This makes .filter() the perfect choice for when you need to return a new Array that may need to be a different length compared to the original Array provided. In other words, the new Array returned is a direct reflection of the conditional check used to filter out item values no longer needed in the original Array.

    示例:

    const originalArr = [1, 2, 3, 4, 5]
    const noEvenNumbersArr = originalArr.filter(n => n%2)
    
    console.log(originalArr)     // console output => [1, 2, 3, 4, 5]
    console.log(noEvenNumbersArr)  // console output => [1, 3, 5]
    

    .REDUCE()

    .reduce()方法与提到的其他 Array 方法一样,遍历给定 Array 中的所有项.它的参数参数不同于 .map() .filter().另外,虽然 .map() .filter()总是返回 Array ,但 .reduce()提供返回和 Object 的功能.与讨论的其他两种方法相比, .reduce()需要更多的时间来正确解释.同样,使用我们已经讨论过的使用 .map() .filter()的内容,可以形成一种解决方案来正确解决最初提出的问题.

    The .reduce() method, like the other Array methods mentioned, loops through all of it's items in a given Array. It's argument parameters are different than .map() and .filter(). Also, while .map() and .filter() ALWAYS return an Array, .reduce() offers the ability to return and Object instead. .reduce() takes a bit more time to properly explain than the other two methods discussed. Also, using what we've discussed using .map() and .filter(), a solution can be formed to properly address the problem originally posed.

    灵魂

    // The Array "items" contains values that need to be removed.
    
    const items = [
      { title: 'Bokningsbar',
        start: moment("2018-04-05 06:00"),
        end: moment("2018-04-05 07:00"),
        allDay: false },
    
      { title: 'Bokningsbar',
        start: moment("2018-04-05 06:00"),
        end: moment("2018-04-05 07:00"),
        allDay: false },
    
      { title: 'Bokningsbar',
        start: moment("2018-04-05 06:00"),
        end: moment("2018-04-05 07:00"),
        allDay: false }, 
    
      { title: 'Bokningsbar',
        start: moment("2018-04-05 06:00"),
        end: moment("2018-04-05 07:00"),
        allDay: false }
    ]
    
    
    // The Array "datesToRemove" contains values that match what needs
    // to be removed from the"items" Array
    
    const datesToRemove = [
      { title: 'Bokningsbar',
        start: moment("2018-04-05 06:00"),
        end: moment("2018-04-05 07:00"),
        allDay: false }
    ]
    

    .filter()方法可以处理解决问题所需的一切...几乎.现在,问题主要围绕两件事,1.不针对另一个项目数组过滤一个项目数组.相反,您尝试针对另一个OBJECTS数组过滤OBJECTS数组.如果这是此处的意图,则可以修改以下内容以检查本机的 Object 方法(和迭代器),例如 Object.keys() Object.values().

    The .filter() method can handle everything needed for a solution to the problem... Almost. The problem now revolves around 2 things specifically, 1. Not filtering an Array of items against another Array of items. Instead, you're trying to filter an Array of OBJECTS against another Array of OBJECTS. If that is the intention here, you can modify the following to check for native Object methods (and iterators) such as Object.keys() and Object.values().

      const mergeUniqueMatches = (catArr) => catArr.filter((elem, pos, arr) => arr.indexOf(elem) == pos)
      const mergedArr = mergeUniqueMatches(items.concat(datesToRemove))  
    

    mergedArr 登录到控制台会显示一个新的 Array .原始数据仍然完好无损.再次,浅拷贝是我们在这里使用的.

    Logging mergedArr to the console gives shows a new Array. The original data is still perfectly untouched. Again, shallow copies are what we are working with here.

    现在的诀窍是消灭" mergedArr .对我们来说幸运的是,ES6/7使这成为小菜一碟.试试:

    Now the trick is to "Dedupe" the mergedArr. Lucky for us, ES6/7 makes this a piece of cake. Try:

    const dedupedArr = [...new Set(mergedArr)]  
    

    尽管需要进一步说明,但您需要进一步澄清.您可以随时提供一个密钥(例如生成一个uuid),并将 items 对象添加到 Array 中,从而使自己更轻松.然后,在该项目移到 datesToRemove Array 之后,您要做的就是关闭实例ID键(uuid)的 .filter().安全地删除正确的项目,而不必担心在此过程中会更改任何数据.

    Moving any further though requires some clarification on your end. You could make this much easier for yourself by providing a key (like generated a uuid) any time and items object is added to the Array. Then after that item moves to the datesToRemove Array, all you need to do is a .filter() off the instance ID key (uuid) to remove the right items safely, and without worrying about mutating any data along the way.

    我将留给您最后两个选择,

    I'll leave you with these two finally alternatives,

      const destructingOptionWithES6 = {
        ...items,
        ...datesToRemove
      }
    
      const ideallyAllYouShouldHaveToDoIsThisFunction = items.filter(val => !datesToRemove.includes(val))
    

    这篇关于用另一个数组删除/过滤对象数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆