Skip to content

Keep arrays as arrays #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
marciorodrigues87 opened this issue Nov 17, 2017 · 6 comments
Closed

Keep arrays as arrays #23

marciorodrigues87 opened this issue Nov 17, 2017 · 6 comments

Comments

@marciorodrigues87
Copy link

Hi guys! First of all, great work on this project!

I was thinking if you find it useful to keep arrays as arrays on the resulting diff object, something like:

      let difference = diff(l[key], r[key])
      if (Array.isArray(l[key])) {
        difference = Object.entries(difference).map(d => d[1])
      }

If it's interesting to you I can submit a PR to do that!

@mattphillips
Copy link
Owner

Hey @marciorodrigues87 by converting the object representation back to an array with:

Object.entries(difference).map(d => d[1]);

you would lose the original index of the array where the difference occured.

Could you (or @webyonet) show me an example of what you would like the difference to look like for a given left and right object with arrays values?

The issue with preserving an array when performing a diff is what do you do with the indices that do not change? There are 3 types of operations that can cause a diff added, deleted and updated and their placement in an array can have knock on affects to the rest of the data structure. I've written out examples of the types of diffs that can occur in an array (not including nested objects but the logic is the same) and highlighted the results of each diff below.

// added (start of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['d', 'a', 'b', 'c'] };
diff(left, right);
/*
{
  alphabet: { 0: 'd', 1: 'a', 2: 'b', 3: 'c' }
}
*/

// added (end of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['a', 'b', 'c', 'd'] };
diff(left, right);
/*
{
  alphabet: { 3: 'd' }
}
*/

// deleted (start of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['b', 'c'] };
diff(left, right);
/*
{
  alphabet: { 0: 'b', 1: 'c', 2: undefined }
}
*/

// deleted (end of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['a', 'b'] };
diff(left, right);
/*
{
  alphabet: { 2: undefined }
}
*/

// updated
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['z', 'b', 'c'] };
diff(left, right);
/*
{
  alphabet: { 0: 'z' }
}
*/

What would you want the output to be? Something like:

// added (start of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['d', 'a', 'b', 'c'] };
diff(left, right);
/*
{
  alphabet: ['d', 'a', 'b', 'c']
}
*/

// added (end of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['a', 'b', 'c', 'd'] };
diff(left, right);
/*
{
  alphabet: [empty, empty, empty, 'd']
}
*/

// deleted (start of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['b', 'c'] };
diff(left, right);
/*
{
  alphabet: ['b', 'c', undefined]
}
*/

// deleted (end of array)
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['a', 'b'] };
diff(left, right);
/*
{
  alphabet: [empty, empty, undefined]
}
*/

// updated
const left = { alphabet: ['a', 'b', 'c'] };
const right = { alphabet: ['z', 'b', 'c'] };
diff(left, right);
/*
{
  alphabet: ['z', empty, empty]
}
*/

Where empty signifies no difference? (This could be achieved by deleting the items from the array which are the same see)

@mattphillips
Copy link
Owner

Closing this for now due to inactivity. Feel free to reopen

@popojargo
Copy link

popojargo commented Aug 30, 2018

@mattphillips I have a use case where the order is not important. It would be perfect if array would be return as arrays.
Anyway we could add some params and use the preserveArray functionalities? I willing to put some time to make it work if necessary

@iMoses
Copy link

iMoses commented Jun 17, 2019

@mattphillips is this library still maintained? If so I have a proposal and am willing to provide a PR.

I don't believe it's possible to add this functionality to the diff method without losing information, but we can certainly add it to all the other, more detailed methods and have them return arrays of what was added and deleted (nothing updates if we ignore the order).

We can take an options argument, or a boolean, to indicate whether to ignore arrays order.
Clean and simple.

@schester44
Copy link

+1

A method that returns arrays as arrays would be very useful. There are times when I don't care about
preserving indices yet do not know the names of the property keys to manually convert the values back to an array.

@antipin
Copy link

antipin commented Nov 25, 2020

+1

Would be useful to have a diff that works like this regarding to arrays:

  1. If both arrays are equal, there is no diff
  2. If updatedObj is different, just keep updatedObj as a result in the diff (so we kind of treat arrays as scalar values)

An example:

const lhs = {
    bar: {
        a1: ['a', 'b'],
        a2: ['j', 'i'],
        a3: ['x', 'y'],

    },
};
 
const rhs = {
    bar: {
        a1: ['a', 'b'],
        a2: ['j'], // <-- 'i' is removed
        a3: ['x', 'y', 'z'], // 'z' is added
    },
    foo: 'bar', // <-- added new prop
};
 
console.log(diff(lhs, rhs)); // =>
/*
{
    bar: {
        a2: ['j'],
        a3: ['x', 'y', 'z']
    },
    foo: 'bar',
};
*/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants