javascript - 如何实现数据比较函数的递归?
问题描述
我的应用程序中有这个帮助函数,它告诉我newData
与oldData
.
如何重构我的getChanges函数以使下面的测试通过?我想我可能需要使这个函数递归,因为它是从自身内部执行的,但我不完全确定如何实现它。
它看起来像这样:
getChanges
辅助功能:
export function getChanges(oldData: Record<string, any>, newData: Record<string, any>): any {
return Object.entries(newData).reduce((changes, [key, newVal]) => {
if (JSON.stringify(oldData[key]) === JSON.stringify(newVal)) return changes
changes[key] = newVal
return changes
}, {} as any)
}
在我的实际测试中,我使用 ava 的 deepEqual 来帮助进行比较。不管出于何种原因,我正在运行的一项测试没有通过。
index.ts 测试 1通过
import test from 'ava'
import { getChanges } from '../src/comparisonHelpers.js'
test('getChanges - flat', (t) => {
const a = getChanges({}, {})
const b = {}
t.deepEqual(a, b)
t.deepEqual(getChanges({ a: 1 }, { a: 1 }), {})
t.deepEqual(getChanges({ a: 1 }, {}), {})
t.deepEqual(getChanges({}, { a: 1 }), { a: 1 })
const oldData = { a: 1, b: 1, c: 1 }
const newData = { x: 1, a: 1, b: 2 }
const result = getChanges(oldData, newData)
const expect = { x: 1, b: 2 }
t.deepEqual(result, expect)
})
index.ts 测试 2未通过
import test from 'ava'
import { getChanges } from '../src/comparisonHelpers.js'
test('getChanges - nested difference', (t) => {
const oldData = { nested: { a: 1, b: 1, c: 1 } }
const newData = { nested: { x: 1, a: 1, b: 2 } }
const res = getChanges(oldData, newData)
t.deepEqual(res, { nested: { x: 1, b: 2 } })
})
基本上,如果测试通过,我预计不会返回任何内容,但是此测试在失败时返回此对象:
{
nested: {
- a: 1,
b: 2,
x: 1,
},
}
我在这里做错了什么阻止了这个测试通过?
干杯!
解决方案
这是一个非常粗略的第一次通过这样的函数(这里命名diff
而不是getChanges
):
const isObject = (o) =>
Object (o) === o
const isEmptyObject = (o) =>
isObject(o) && Object .keys (o) .length == 0
const diff = (a, b) =>
Object .fromEntries (
[... (new Set ([...Object .keys (a), ...Object.keys(b)]))].flatMap (
(k) =>
k in a
? k in b
? isObject (a [k])
? isObject (b [k])
? [[k, diff (a [k], b [k])]] // <--- recursive call here
: [[k, b [k]]]
: a[k] == b [k]
? []
: [[k, b [k]]]
: [[k, undefined]]
: [[k, b [k]]]
) .filter (([k, v]) => !isEmptyObject(v))
)
const oldData = {nested: { a: 1, b: 1, c: 1 }, foo: {x: 3, y: 5}, bar: {x: 1}, qux: {x: 6}}
const newData = {nested: { x: 1, a: 1, b: 2 }, foo: {x: 4, y: 5}, bar: {x: 1}, corge: {x: 6}}
console .log (diff (oldData, newData))
.as-console-wrapper {max-height: 100% !important; top: 0}
这是非常简单的,并且有些输入不起作用,尤其是那些故意包含undefined
值的输入。它还将通过设计包括undefined
新数据中缺少的键的值。但是不包括它们很容易:我相信只需在函数中更改[[k, undefined]]
为即可[]
通过您的测试用例。
请注意,谢谢(用户)建议的答案使用比这更好的差异格式:对于所有已更改的键,它包含left
和right
属性来为您提供值,跳过那些根本不存在的。这将让您明确地重播或恢复差异。使用此处的格式,这并不总是有效。
这里的流程中也有太多相同输出的副本。我猜想,我们也许可以减少涉及的案件。
推荐阅读
- r - Ops.factor 中的错误(实际,预测):因子的水平集与包 iml 中的 Featureimp 不同
- c# - 在 xaml 中选中一个复选框以取消选中另一个复选框
- c++ - 有什么方法可以设置用 g++ 构建的二进制文件的版本吗?
- java - 需要一种更有效的方法将 JDBC 结果集转换为 JSON 数组
- python - 有效地从多个列表中进行随机选择
- r - 将文本标签添加到 tmap 图中
- java - 从arrayList加载uri字符串时,格式错误的url异常没有协议
- python - 如何在openpyxl中将预先计算的误差线添加到条形图中
- c# - 将 Mosquitto 主题匹配功能从 C 翻译成 C#
- framebuffer - 如何保持粒子之间的协调以及哪个纹理像素包含每个人的信息?