# array\_symmetric\_difference

Returns elements that exist in either array but not in both. Similar to set symmetric difference (A △ B) or XOR operation.

```liquid
{% assign old_tags = "sale,featured,new" | split: "," %}
{% assign new_tags = "featured,bestseller,clearance" | split: "," %}

{% assign changed_tags = old_tags | array_symmetric_difference: new_tags %}
{% log changed_tags | join: ", " %}
```

Output:

```
sale, new, bestseller, clearance
```

#### Syntax

```liquid
{{ arrayA | array_symmetric_difference: arrayB }}
```

| Parameter | Description  |
| --------- | ------------ |
| `arrayA`  | First array  |
| `arrayB`  | Second array |

#### Visual Representation

```
Array A: [1, 2, 3, 4, 5]
Array B: [3, 4, 5, 6, 7]

Result:  [1, 2, 6, 7]  (elements in A OR B, but NOT both)
```

This is equivalent to: `(A - B) + (B - A)`

#### Examples

**Detect all tag changes:**

```liquid
{% assign old_tags = product_before.tags | split: ", " %}
{% assign new_tags = product_after.tags | split: ", " %}

{% assign all_changes = old_tags | array_symmetric_difference: new_tags %}

{% if all_changes.size > 0 %}
  {% assign added_tags = new_tags | array_difference: old_tags %}
  {% assign removed_tags = old_tags | array_difference: new_tags %}

  {% log "Tags added: " | append: added_tags | join: ", " %}
  {% log "Tags removed: " | append: removed_tags | join: ", " %}
{% else %}
  {% log "No tag changes detected" %}
{% endif %}
```

**Find inventory discrepancies:**

```liquid
{% assign system_skus = inventory_system | map: "sku" %}
{% assign physical_skus = physical_count | map: "sku" %}

{% assign discrepancies = system_skus | array_symmetric_difference: physical_skus %}

{% if discrepancies.size > 0 %}
  {% log "Inventory discrepancies found: " | append: discrepancies.size %}

  {% assign missing_from_physical = system_skus | array_difference: physical_skus %}
  {% assign missing_from_system = physical_skus | array_difference: system_skus %}

  {% log "In system but not found physically:" %}
  {% log missing_from_physical %}

  {% log "Found physically but not in system:" %}
  {% log missing_from_system %}
{% endif %}
```

**Compare collection membership:**

```liquid
{% assign collection_a_ids = collection_a.products | map: "id" %}
{% assign collection_b_ids = collection_b.products | map: "id" %}

{% assign unique_to_either = collection_a_ids | array_symmetric_difference: collection_b_ids %}
{% assign in_both = collection_a_ids | array_intersection: collection_b_ids %}

{% log "Products unique to one collection: " | append: unique_to_either.size %}
{% log "Products in both collections: " | append: in_both.size %}
```

**Sync differences between systems:**

```liquid
{% assign shopify_product_ids = shopify_products | map: "external_id" %}
{% assign erp_product_ids = erp_products | map: "id" %}

{% assign out_of_sync = shopify_product_ids | array_symmetric_difference: erp_product_ids %}

{% if out_of_sync.size > 0 %}
  {% log "Products out of sync between systems:" %}

  {% comment %} Products in Shopify but not ERP {% endcomment %}
  {% assign shopify_only = shopify_product_ids | array_difference: erp_product_ids %}
  {% for id in shopify_only %}
    {% log "Shopify only: " | append: id %}
  {% endfor %}

  {% comment %} Products in ERP but not Shopify {% endcomment %}
  {% assign erp_only = erp_product_ids | array_difference: shopify_product_ids %}
  {% for id in erp_only %}
    {% log "ERP only: " | append: id %}
  {% endfor %}
{% endif %}
```

**Detect permission changes:**

```liquid
{% assign old_permissions = user_before.permissions %}
{% assign new_permissions = user_after.permissions %}

{% assign permission_changes = old_permissions | array_symmetric_difference: new_permissions %}

{% if permission_changes.size > 0 %}
  {% assign granted = new_permissions | array_difference: old_permissions %}
  {% assign revoked = old_permissions | array_difference: new_permissions %}

  {% if granted.size > 0 %}
    {% log "Permissions granted: " | append: granted | join: ", " %}
  {% endif %}

  {% if revoked.size > 0 %}
    {% log "Permissions revoked: " | append: revoked | join: ", " %}
  {% endif %}
{% endif %}
```

#### Performance

Uses Set-based lookup for O(n + m) time complexity instead of O(n × m + m × n).

| Array A Size | Array B Size | Operations |
| ------------ | ------------ | ---------- |
| 1,000        | 1,000        | \~4,000    |
| 10,000       | 10,000       | \~40,000   |
| 100,000      | 100,000      | \~400,000  |

#### Notes

* Both inputs must be arrays; throws error otherwise
* Result contains elements from arrayA first, then elements from arrayB
* Returns empty array if both arrays contain exactly the same elements
* Useful for detecting any kind of change between two states
* Comparison uses strict equality (===)
* See also: `array_difference`, `array_intersection`, `array_equal`
