两个对象之间的通用深度差异

2024-01-08

我有两个对象:oldObj and newObj.

数据在oldObj用于填充表单并且newObj是用户更改此表单中的数据并提交的结果。

两个物体都很深,即。它们具有对象或对象数组等属性 - 它们可以是 n 层深,因此 diff 算法需要递归。

现在我需要的不仅仅是弄清楚更改了什么(如添加/更新/删除)oldObj to newObj,以及如何最好地表示它。

到目前为止,我的想法是建立一个genericDeepDiffBetweenObjects将返回表单上的对象的方法{add:{...},upd:{...},del:{...}}但后来我想:以前肯定有人需要这个。

那么...有谁知道一个库或一段代码可以做到这一点,并且可能有更好的方式来表示差异(以仍然是 JSON 可序列化的方式)?

Update:

我想到了一种更好的方法来表示更新的数据,使用与newObj,但是将所有属性值转换为表单上的对象:

{type: '<update|create|delete>', data: <propertyValue>}

So if newObj.prop1 = 'new value' and oldObj.prop1 = 'old value'它会设置returnObj.prop1 = {type: 'update', data: 'new value'}

更新2:

当我们使用数组属性时,事情变得非常棘手,因为数组[1,2,3]应算作等于[2,3,1],这对于基于值的类型(如 string、int 和 bool)的数组来说足够简单,但当涉及到引用类型(如对象和数组)的数组时,就变得非常难以处理。

应发现相等的示例数组:

[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]

不仅检查这种类型的深度值相等性非常复杂,而且找出一种表示可能发生的变化的好方法。


我写了一个小类,正在做你想做的事情,你可以测试一下here http://jsfiddle.net/cs5d3uwn/.

唯一与你的建议不同的是我不考虑

[1,[{c: 1},2,3],{a:'hey'}]

and

[{a:'hey'},1,[3,{c: 1},2]]

相同,因为我认为如果数组元素的顺序不同,则数组不相等。当然,如果需要的话可以更改。此外,此代码还可以进一步增强,以将函数作为参数,用于根据传递的原始值以任意方式格式化 diff 对象(现在这项工作是通过“compareValues”方法完成的)。

var deepDiffMapper = function () {
  return {
    VALUE_CREATED: 'created',
    VALUE_UPDATED: 'updated',
    VALUE_DELETED: 'deleted',
    VALUE_UNCHANGED: 'unchanged',
    map: function(obj1, obj2) {
      if (this.isFunction(obj1) || this.isFunction(obj2)) {
        throw 'Invalid argument. Function given, object expected.';
      }
      if (this.isValue(obj1) || this.isValue(obj2)) {
        return {
          type: this.compareValues(obj1, obj2),
          data: obj1 === undefined ? obj2 : obj1
        };
      }

      var diff = {};
      for (var key in obj1) {
        if (this.isFunction(obj1[key])) {
          continue;
        }

        var value2 = undefined;
        if (obj2[key] !== undefined) {
          value2 = obj2[key];
        }

        diff[key] = this.map(obj1[key], value2);
      }
      for (var key in obj2) {
        if (this.isFunction(obj2[key]) || diff[key] !== undefined) {
          continue;
        }

        diff[key] = this.map(undefined, obj2[key]);
      }

      return diff;

    },
    compareValues: function (value1, value2) {
      if (value1 === value2) {
        return this.VALUE_UNCHANGED;
      }
      if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {
        return this.VALUE_UNCHANGED;
      }
      if (value1 === undefined) {
        return this.VALUE_CREATED;
      }
      if (value2 === undefined) {
        return this.VALUE_DELETED;
      }
      return this.VALUE_UPDATED;
    },
    isFunction: function (x) {
      return Object.prototype.toString.call(x) === '[object Function]';
    },
    isArray: function (x) {
      return Object.prototype.toString.call(x) === '[object Array]';
    },
    isDate: function (x) {
      return Object.prototype.toString.call(x) === '[object Date]';
    },
    isObject: function (x) {
      return Object.prototype.toString.call(x) === '[object Object]';
    },
    isValue: function (x) {
      return !this.isObject(x) && !this.isArray(x);
    }
  }
}();


var result = deepDiffMapper.map({
  a: 'i am unchanged',
  b: 'i am deleted',
  e: {
    a: 1,
    b: false,
    c: null
  },
  f: [1, {
    a: 'same',
    b: [{
      a: 'same'
    }, {
      d: 'delete'
    }]
  }],
  g: new Date('2017.11.25')
}, {
  a: 'i am unchanged',
  c: 'i am created',
  e: {
    a: '1',
    b: '',
    d: 'created'
  },
  f: [{
    a: 'same',
    b: [{
      a: 'same'
    }, {
      c: 'create'
    }]
  }, 1],
  g: new Date('2017.11.25')
});
console.log(result);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

两个对象之间的通用深度差异 的相关文章

随机推荐

  • 使用 io.TextIOWrapper 包装打开的流

    如何包装一个开放的二进制流 Python 2file Python 3io BufferedReader an io BytesIO 在一个io TextIOWrapper 我正在尝试编写不改变即可工作的代码 在 Python 2 上运行
  • Xcode 6 和 Swift 中视图之间类似 Snapchat 的滑动导航)

    我一直在尝试使用滑动手势识别器和嵌入式导航控制器在我的应用程序中的视图控制器之间实现滑动导航 但它看起来与 Snapchat 的导航并不接近 实现搜索功能最有效 最合适的方法是什么 我确实是 Swift 和编程的新手 我会很感激每一个有用的
  • 找不到模块错误:没有名为“chart_studio”的模块

    I run pip install chart studio在 jupyter 笔记本中 然后运行这段代码时 import numpy as np import pandas as pd import cufflinks as cf imp
  • 如何用JQ补数字?

    我想向数字中的字符串添加前导 尾随零 结果字符串需要包含 01 或 001 而不是 1 我注意到项目https github com joelpurra jq zeros但我从包管理器 dnf fedora 安装了 jq 所以需要一些jqn
  • 绑定复选框列表

    我需要一种简单的方法来绑定复选框列表asp net C 我从数据库 Id Name 和 IsActive 中提取 3 列 Id 和 Name 我想通过它的名字就可以清楚地看出 IsActive 将用于显示选中和未选中的框 我只是想知道 数据
  • 在 Angular 2 中从子组件更新父组件属性

    我在用着 input从父组件接收属性 以便激活子组件元素之一中的 CSS 类 我能够从父母那里接收财产并激活班级 但这只有效一次 我从父级接收的属性是一个布尔数据类型 当我将其状态设置为false从子组件开始 它在父组件中不会改变 Plun
  • webpack 4 给出背景: url([object Module]) 作为背景图像

    我在设置 web pack 4 和 svg sprite loader 将 svg 图标渲染为背景图像时遇到问题 我遵循 svg sprite loader 官方文档中的这些说明 https github com kisenka svg s
  • 使用 OpenCV 和 PyAudio 同步音频和视频

    我已经让 OpenCV 和 PyAudio 都工作了 但是我不确定如何将它们同步在一起 我无法从 OpenCV 获取帧速率并测量帧时时刻刻变化的调用时间 然而 对于 PyAudio 来说 它的基础是获取一定的采样率 我如何将它们同步到相同的
  • SqlAlchemy 连接字符串[重复]

    这个问题在这里已经有答案了 我遇到了非常奇怪的问题 我使用 sqlalchemy 的解决方案无法连接到数据库 这取决于我使用的密码 例如 以下记录工作正常 PWD 123123123 USR test user SQLALCHEMY DAT
  • 修复 OCaml 中的数据类型

    Haskell 中的以下数据类型如何用 OCaml 或 SML 表示 newtype Fix f In f Fix f 我已经在邮件列表上回答了这个问题 https sympa inria fr sympa arc caml list 20
  • R.java 文件实际上做什么以及如何做

    我一直在研究一个简单的 android 教程 在浏览项目文件夹时我发现了这个R java文件输入gen文件夹 当我打开时 我觉得它很乱 first R本身就是一个class it had multiple Inner classes定义在例
  • 如何在格式为“0000-00-00T00:00:00+00:00”的字符串上使用 datetime.strptime?

    由于我的应用程序的情况 我更愿意使用datetime strptime代替dateutil parser 看完之后docs https docs python org 3 library datetime html strftime str
  • 将代码添加到 __init__.py

    我正在研究 django 中的模型系统是如何工作的 我注意到一些我不明白的东西 我知道你创建了一个空的 init pyfile 来指定当前目录是一个包 你可以在其中设置一些变量 init py以便 import 正常工作 但是 django
  • C# 从 URL 下载文件

    谁能告诉我如何从该 URL 下载 C 程序中的文件 http www cryptopro ru products cades plugin get 2 0 http www cryptopro ru products cades plugi
  • 事件溯源基础设施实施

    我在我的应用程序中实现了事件源和 CQRS 模式 我的灵感来自于CQRS 旅程 https msdn microsoft com en us library jj554200 aspx我在哪里下载了示例代码 在那里 我找到了事件源的完整基础
  • 如何将数组作为参数传递给 shell 脚本并获取数组

    我将多个参数传递给 shell 脚本 在该脚本中 我想创建一个从第二个参数到最后一个参数的数组 我可以在下面做到这一点 arg 1 shift while 1 do emailID emailID 1 shift done 我想将此 ema
  • OAuth 2 Google API 刷新令牌为空

    我正在开发一个 Asp NET MVC5 应用程序按照这个谷歌示例代码 https developers google com api client library dotnet guide aaa oauth 我希望应用程序经过身份验证并
  • CMB2 可重复组显示

    我正在使用 Custom Metaboxes 2 但无法在前端显示可重复的组值 我有一个带有单个文本字段的可重复组 我用这个作为指导 https github com WebDevStudios CMB2 wiki Field Types
  • 从 MVC Web API 响应中删除 XML 命名空间属性

    我从 MVC Web Api 收到以下响应
  • 两个对象之间的通用深度差异

    我有两个对象 oldObj and newObj 数据在oldObj用于填充表单并且newObj是用户更改此表单中的数据并提交的结果 两个物体都很深 即 它们具有对象或对象数组等属性 它们可以是 n 层深 因此 diff 算法需要递归 现在