How to implement checking and ignoring when an array/object path is *moved* when diffing arrays in JavaScript?

独自空忆成欢 提交于 2021-01-29 19:20:54

问题


I have seen flitbit/diff but it says:

Changes to arrays are recorded simplistically. We care most about the shape of the structure; therefore we don't take the time to determine if an object moved from one slot in the array to another....

So doesn't work there.

How would you implement this? It seems very hard. Is it possible to build off one of these existing libraries to ignore array moves? Or how would you implement it directly from scratch?

My use case is, I want to keep track of all changes made to a JSON object in order that people get points/paid for every change they make. But I don't want to give points if people just delete an array path and then add it back again at a different position in the UI, that would be cheating :)

I started by trying to think of flattening the paths, then using regexes on the paths, but that doesn't seem like it'll work:

const flat = require('flat')

const compute = (_a, _b) => {
  const a = flat(_a)
  const b = flat(_b)

  let r_a = []
  for (let k_a in a) {
    r_a.push([
      k_a,
      new RegExp(`^` + k_a.replace(/\./g, '\\.').replace(/\d+/g, '\\d+') + `$`)
    ])
  }

  let r_b = []
  for (let k_b in b) {
    r_b.push([
      k_b,
      new RegExp(`^` + k_b.replace(/\./g, '\\.').replace(/\d+/g, '\\d+') + `$`)
    ])
  }

  let diff = []
  for (let i = 0, n = r_a.length; i < n; i++) {
    let [k_a, r_a_i] = r_a[i]
    let matches = false
    k_b_loop:
    for (let k_b in b) {
      if (r_a_i.test(k_b) && a[k_a] === b[k_b]) {
        matches = true
        break k_b_loop
      }
    }
    if (!matches) {
      diff.push({
        type: 'remove',
        path: k_a
      })
    }
  }

  for (let i = 0, n = r_b.length; i < n; i++) {
    let [k_b, r_b_i] = r_b[i]
    let matches = false
    k_a_loop:
    for (let k_a in a) {
      if (r_b_i.test(k_a) && b[k_b] === a[k_a]) {
        matches = true
        break k_a_loop
      }
    }
    if (!matches) {
      diff.push({
        type: 'create',
        path: k_b
      })
    }
  }

  return diff
}

const test1 = () => {
  const a = { 
    a: [
      { a: 1, b: 2 },
      { a: 1, b: 3 }
    ],
    b: 1,
    c: 2
  }
  const b = { 
    a: [
      { a: 1, b: 3 },
      { a: 1, b: 1 },
      { a: 1, b: 4 }
    ],
    c: 3
  }
  const diff = computeDiff(a, b)
  console.log(diff)
}

test1()

来源:https://stackoverflow.com/questions/64635260/how-to-implement-checking-and-ignoring-when-an-array-object-path-is-moved-when

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!