Skip to content

Commit 6d09c01

Browse files
authored
chore: improve list-diff performance (#27)
* chore: improve list-diff perf * chore: update readme
1 parent 8ffb9ea commit 6d09c01

File tree

3 files changed

+117
-116
lines changed

3 files changed

+117
-116
lines changed

README.md

+15-15
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ This library compares two arrays or objects and returns a full diff of their dif
1616

1717
## WHY YOU SHOULD USE THIS LIBRARY
1818

19-
All other existing solutions return a strange diff format that often requires additional parsing. They are also limited to object comparison.
19+
Most existing solutions return a confusing diff format that often requires extra parsing. They are also limited to object comparison.
2020

21-
**Superdiff** gives you a complete diff for both array <u>and</u> objects in a very readable format. Last but not least, it's battle-tested, has zero dependencies, and is super fast.
21+
**Superdiff** provides a complete and readable diff for both arrays **and** objects. Plus, it's battle-tested, has zero dependencies, and is super fast.
2222

2323
Import. Enjoy. 👍
2424

@@ -66,7 +66,7 @@ isObject(data)
6666
import { getObjectDiff } from "@donedeal0/superdiff";
6767
```
6868

69-
Compares two objects and return a diff for each value and their potential subvalues. Supports deeply nested objects with any kind of values.
69+
Compares two objects and returns a diff for each value and its possible subvalues. Supports deeply nested objects of any value type.
7070

7171
#### FORMAT
7272

@@ -87,7 +87,7 @@ options?: {
8787
- `prevData`: the original object.
8888
- `nextData`: the new object.
8989
- `options`
90-
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays have the same value, just not in the same order.
90+
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays contain the same values, just in a different order.
9191
- `showOnly`: returns only the values whose status you are interested in. It takes two parameters:
9292

9393
- `statuses`: status you want to see in the output (e.g. `["added", "equal"]`)
@@ -226,8 +226,8 @@ Compares two arrays and returns a diff for each entry. Supports duplicate values
226226
- `nextList`: the new list.
227227
- `options`
228228
- `showOnly` gives you the option to return only the values whose status you are interested in (e.g. `["added", "equal"]`).
229-
- `referenceProperty` will consider an object to be updated instead of added or deleted if one of its properties remains stable, such as its `id`. This option has no effect on other datatypes.
230-
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays have the same value, just not in the same order.
229+
- `referenceProperty` will consider an object to be `updated` rather than `added` or `deleted` if one of its properties remains stable, such as its `id`. This option has no effect on other datatypes.
230+
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays contain the same values, just in a different order.
231231
- `considerMoveAsUpdate`: if set to `true` a `moved` value will be considered as `updated`.
232232

233233
**Output**
@@ -328,18 +328,18 @@ Streams the diff of two object lists, ideal for large lists and maximum performa
328328
329329
- `prevList`: the original object list.
330330
- `nextList`: the new object list.
331-
- `referenceProperty`: a common property in all the objects of your lists (e.g. `id`).
331+
- `referenceProperty`: a property common to all objects in your lists (e.g. `id`).
332332
- `options`
333-
- `chunksSize` the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff by chunk, `10` = 10 object diffs by chunk).
333+
- `chunksSize` the number of object diffs returned by each streamed chunk. (e.g. `0` = 1 object diff per chunk, `10` = 10 object diffs per chunk).
334334
- `showOnly` gives you the option to return only the values whose status you are interested in (e.g. `["added", "equal"]`).
335335
- `considerMoveAsUpdate`: if set to `true` a `moved` value will be considered as `updated`.
336336
337337
**Output**
338338
339-
The objects diff are grouped in arrays - called `chunks` - and are consumed thanks to an event listener. You have access to 3 events:
339+
The objects diff are grouped into arrays - called `chunks` - and are consumed thanks to an event listener. You have access to 3 events:
340340
- `data`: to be notified when a new chunk of object diffs is available.
341-
- `finish`: to be notified when the stream is complete.
342-
- `error`: to be notified of an error during the stream.
341+
- `finish`: to be notified when the stream is finished.
342+
- `error`: to be notified if an error occurs during the stream.
343343
344344
```ts
345345
interface StreamListener<T extends Record<string, unknown>> {
@@ -442,7 +442,7 @@ diff.on("error", (err) => console.log(err))
442442
import { isEqual } from "@donedeal0/superdiff";
443443
```
444444
445-
Checks whether two values are equal.
445+
Tests whether two values are equal.
446446
447447
#### FORMAT
448448
@@ -455,9 +455,9 @@ options: {
455455
ignoreArrayOrder: boolean; // false by default
456456
},
457457
```
458-
- `a`: the value to compare to the value `b`.
459-
- `b`: the value that will be compared to the value `a`.
460-
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays have the same value, just not in the same order.
458+
- `a`: the value to be compared to the value `b`.
459+
- `b`: the value to be compared to the value `a`.
460+
- `ignoreArrayOrder`: if set to `true`, `["hello", "world"]` and `["world", "hello"]` will be treated as `equal`, because the two arrays contain the same values, just in a different order.
461461
462462
#### USAGE
463463

src/lib/list-diff/index.ts

+12-12
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,26 @@ export const getListDiff = <T>(
8383
return formatSingleListDiff(prevList as T[], LIST_STATUS.DELETED, options);
8484
}
8585
const diff: ListDiff["diff"] = [];
86-
const prevIndexMatches: number[] = [];
86+
const prevIndexMatches = new Set<number>();
87+
8788
nextList.forEach((nextValue, i) => {
8889
const prevIndex = prevList.findIndex((prevValue, prevIdx) => {
90+
if (prevIndexMatches.has(prevIdx)) {
91+
return false;
92+
}
8993
if (isReferencedObject(prevValue, options.referenceProperty)) {
9094
if (isObject(nextValue)) {
91-
return (
92-
isEqual(
93-
prevValue[options.referenceProperty as string],
94-
nextValue[options.referenceProperty as string],
95-
) && !prevIndexMatches.includes(prevIdx)
95+
return isEqual(
96+
prevValue[options.referenceProperty as string],
97+
nextValue[options.referenceProperty as string],
9698
);
9799
}
98100
return false;
99101
}
100-
return (
101-
isEqual(prevValue, nextValue) && !prevIndexMatches.includes(prevIdx)
102-
);
102+
return isEqual(prevValue, nextValue);
103103
});
104104
if (prevIndex > -1) {
105-
prevIndexMatches.push(prevIndex);
105+
prevIndexMatches.add(prevIndex);
106106
}
107107
const indexDiff = prevIndex === -1 ? null : i - prevIndex;
108108
if (indexDiff === 0 || options.ignoreArrayOrder) {
@@ -141,8 +141,8 @@ export const getListDiff = <T>(
141141
});
142142

143143
prevList.forEach((prevValue, i) => {
144-
if (!prevIndexMatches.includes(i)) {
145-
return diff.splice(i, 0, {
144+
if (!prevIndexMatches.has(i)) {
145+
return diff.push({
146146
value: prevValue,
147147
prevIndex: i,
148148
newIndex: null,

0 commit comments

Comments
 (0)