---
name: join_by_key
kind: function
lang: py
domain: core
version: "1.0.0"
purity: pure
signature: "def join_by_key(left: list[dict], right: list[dict], key: str, how: str = 'inner') -> list[dict]"
description: "Join de dos listas de dicts por una clave comun. Soporta inner, left, right y outer. Campos duplicados del right se sufijan con _right. Algoritmo O(n+m)."
tags: [tabular, join, merge, python, core]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: []
params:
  - name: left
    desc: "Lista izquierda de diccionarios a joinear"
  - name: right
    desc: "Lista derecha de diccionarios a joinear"
  - name: key
    desc: "Nombre de la clave común para hacer matching"
  - name: how
    desc: "Tipo de join: 'inner', 'left', 'right' u 'outer'"
output: "Lista de diccionarios resultantes del join con campos renombrados si hay conflicto"
tested: true
tests:
  - "Inner join solo matches"
  - "Left join todos los left con None para right sin match"
  - "Right join"
  - "Outer join"
  - "Campos duplicados con sufijo _right"
  - "Key ausente en alguna fila"
test_file_path: "python/functions/core/join_by_key_test.py"
file_path: "python/functions/core/join_by_key.py"
---

## Ejemplo

```python
left = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
right = [{"id": 1, "dept": "eng"}, {"id": 3, "dept": "sales"}]

join_by_key(left, right, key="id", how="inner")
# [{"id": 1, "name": "Alice", "dept": "eng"}]

join_by_key(left, right, key="id", how="left")
# [{"id": 1, "name": "Alice", "dept": "eng"},
#  {"id": 2, "name": "Bob", "dept": None}]
```

## Notas

Funcion pura sin dependencias externas.
El algoritmo indexa right en O(n) y luego itera left en O(m), total O(n+m).
Los campos de right que colisionan con campos de left (excepto la clave) se renombran con sufijo _right.
