如何实现数据比较功能的递归?

How to implement recursion for data comparison function?

我的应用程序中有这个辅助函数,它告诉我 newDataoldData 相比的变化。

如何重构我的 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 } })
})

基本上,如果测试通过,我不希望返回任何内容,但是这个测试 returns 这个对象在失败时:

{
      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]] 更改为 [],我相信这将通过您的测试用例。

请注意,(用户)建议的答案使用比这更好的 diff 格式:对于所有已更改的键,它包括 leftright 属性以提供你的价值,跳过那些根本不存在的。这会让你明确地重播或恢复差异。使用此处的格式,这并不总是有效。

这里的流程中也有太多相同输出的副本。我猜想一下,我们也许可以减少涉及的案例。