# diffArrays

```ts
import { diffArrays } from 'cx/data';
```


`diffArrays` compares two arrays and returns the differences: added, changed, unchanged, and removed items.

```tsx
import { diffArrays, createModel } from "cx/data";
import { Controller } from "cx/ui";
import { Button, Grid } from "cx/widgets";

interface Item {
  id: number;
  name: string;
}

interface DiffResult {
  added: Item[];
  changed: { before: Item; after: Item }[];
  unchanged: Item[];
  removed: Item[];
}

interface Model {
  oldItems: Item[];
  newItems: Item[];
  diff: DiffResult;
}

const m = createModel<Model>();

// Shared object instances - same reference = unchanged
const apple = { id: 1, name: "Apple" };
const banana = { id: 2, name: "Banana" };
const cherry = { id: 3, name: "Cherry" };

class PageController extends Controller {
  onInit() {
    // Apple is unchanged (same reference)
    // Banana changed to Blueberry (different object, same id)
    // Cherry removed
    // Date added
    this.store.set(m.oldItems, [apple, banana, cherry]);
    this.store.set(m.newItems, [
      apple, // same reference = unchanged
      { id: 2, name: "Blueberry" }, // new object with same id = changed
      { id: 4, name: "Date" }, // new id = added
    ]);
    this.computeDiff();
  }

  computeDiff() {
    const oldItems = this.store.get(m.oldItems);
    const newItems = this.store.get(m.newItems);
    const diff = diffArrays(oldItems, newItems, (item) => item.id);
    this.store.set(m.diff, diff);
  }

  scenario1() {
    const a = { id: 1, name: "A" };
    this.store.set(m.oldItems, [a]);
    this.store.set(m.newItems, [a, { id: 2, name: "B" }, { id: 3, name: "C" }]);
    this.computeDiff();
  }

  scenario2() {
    const a = { id: 1, name: "A" };
    const b = { id: 2, name: "B" };
    const c = { id: 3, name: "C" };
    this.store.set(m.oldItems, [a, b, c]);
    this.store.set(m.newItems, [b]);
    this.computeDiff();
  }

  scenario3() {
    const oldA = { id: 1, name: "Old A" };
    const b = { id: 2, name: "B" };
    this.store.set(m.oldItems, [oldA, b]);
    this.store.set(m.newItems, [{ id: 1, name: "New A" }, { id: 3, name: "C" }]);
    this.computeDiff();
  }

  reset() {
    this.onInit();
  }
}

export default (
  <div controller={PageController}>
    <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px">
      <div>
        <h4 style="margin: 0 0 8px">Old Array</h4>
        <Grid
          records={m.oldItems}
          columns={[
            { header: "ID", field: "id" },
            { header: "Name", field: "name" },
          ]}
        />
      </div>
      <div>
        <h4 style="margin: 0 0 8px">New Array</h4>
        <Grid
          records={m.newItems}
          columns={[
            { header: "ID", field: "id" },
            { header: "Name", field: "name" },
          ]}
        />
      </div>
    </div>

    <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 16px">
      <div>
        <h4 style="margin: 0 0 8px; color: green">Added</h4>
        <Grid
          records={m.diff.added}
          columns={[
            { header: "ID", field: "id" },
            { header: "Name", field: "name" },
          ]}
        />
      </div>
      <div>
        <h4 style="margin: 0 0 8px; color: orange">Changed</h4>
        <Grid
          records={m.diff.changed}
          columns={[
            { header: "Before", field: "before.name" },
            { header: "After", field: "after.name" },
          ]}
        />
      </div>
      <div>
        <h4 style="margin: 0 0 8px; color: gray">Unchanged</h4>
        <Grid
          records={m.diff.unchanged}
          columns={[
            { header: "ID", field: "id" },
            { header: "Name", field: "name" },
          ]}
        />
      </div>
      <div>
        <h4 style="margin: 0 0 8px; color: red">Removed</h4>
        <Grid
          records={m.diff.removed}
          columns={[
            { header: "ID", field: "id" },
            { header: "Name", field: "name" },
          ]}
        />
      </div>
    </div>

    <div style="display: flex; gap: 8px; flex-wrap: wrap">
      <Button onClick="scenario1">Add Items</Button>
      <Button onClick="scenario2">Remove Items</Button>
      <Button onClick="scenario3">Mixed Changes</Button>
      <Button onClick="reset">Reset</Button>
    </div>
  </div>
);

```

## Signature

```ts
function diffArrays<T>(
  oldArray: T[],
  newArray: T[],
  keyFn?: (item: T) => any,
): DiffResult<T>;

interface DiffResult<T> {
  added: T[];
  changed: { before: T; after: T }[];
  unchanged: T[];
  removed: T[];
}
```

## Parameters

| Parameter  | Type       | Default    | Description                               |
| ---------- | ---------- | ---------- | ----------------------------------------- |
| `oldArray` | `T[]`      |            | The original array.                       |
| `newArray` | `T[]`      |            | The new array to compare against.         |
| `keyFn`    | `function` | `(e) => e` | Function to extract unique key from item. |

## Return Value

Returns an object with four arrays:

| Property    | Type                        | Description                                  |
| ----------- | --------------------------- | -------------------------------------------- |
| `added`     | `T[]`                       | Items in new array but not in old.           |
| `changed`   | `{ before: T; after: T }[]` | Items with same key but different reference. |
| `unchanged` | `T[]`                       | Items with same key and reference.           |
| `removed`   | `T[]`                       | Items in old array but not in new.           |

## Examples

### With objects

```ts
const old = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
];

const updated = [
  { id: 1, name: "Alice" }, // unchanged (same reference)
  { id: 2, name: "Bobby" }, // changed (different object)
  { id: 3, name: "Carol" }, // added
];

const diff = diffArrays(old, updated, (item) => item.id);
// {
//   added: [{ id: 3, name: "Carol" }],
//   changed: [{ before: { id: 2, name: "Bob" }, after: { id: 2, name: "Bobby" } }],
//   unchanged: [{ id: 1, name: "Alice" }],
//   removed: []
// }
```

### With primitives

```ts
const old = [1, 2, 3];
const updated = [2, 3, 4];

const diff = diffArrays(old, updated);
// {
//   added: [4],
//   changed: [],
//   unchanged: [2, 3],
//   removed: [1]
// }
```

## Use Cases

- Synchronizing local state with server data
- Showing what changed after an edit
- Optimizing updates by only processing changed items
- Generating change logs or audit trails

## See Also

- [updateArray](/docs/utilities/update-array) - Update items in array
- [filter](/docs/utilities/filter) - Filter array items