# `Yog.IO.List`
[🔗](https://github.com/code-shoily/yog_ex/blob/v0.97.0/lib/yog/io/list.ex#L1)

Adjacency list import/export for graph serialization.

Adjacency lists are a compact way to represent sparse graphs where each node
stores only its neighbors. This format is commonly used in:
- Algorithm competitions and textbooks
- Graph database exports
- Network analysis tools
- Configuration files

## Format

Each line represents one node and its neighbors:

```
node_id: neighbor1 neighbor2 neighbor3...
```

For weighted graphs, neighbors include weights:

```
node_id: neighbor1,weight1 neighbor2,weight2...
```

## Examples

Simple unweighted adjacency list:

```
1: 2 3
2: 3 4
3: 4
4:
```

Weighted adjacency list:

```
1: 2,5 3,10
2: 3,2
3: 4,7
```

## Limitations

This format is intended for simple graphs where:
- Node IDs are integers or strings.
- Edge weights are numbers or maps with a `"weight"` key.

For graphs with complex node IDs (like tuples) or rich metadata, use `Yog.IO.JSON`
or `Yog.IO.GEXF` instead.

## Use Cases

- Importing graphs from text files and databases
- Human-readable graph representation
- Sparse graph serialization
- Algorithm competition input format
- Adjacency matrix conversion

## See Also

- `Yog.IO.Matrix` - Dense adjacency matrix format
- `Yog.IO.JSON` - JSON graph format

# `adjacency_entry`

```elixir
@type adjacency_entry() :: {Yog.node_id(), [{Yog.node_id(), number()}]}
```

Adjacency list entry: {node_id, [{neighbor_id, weight}]}

# `from_list`

```elixir
@spec from_list(:directed | :undirected, [adjacency_entry()]) :: Yog.graph()
```

Creates a graph from an adjacency list.

## Parameters

- `type` - `:directed` or `:undirected`
- `entries` - List of `{node_id, neighbors}` tuples where neighbors is a list
  of `{neighbor_id, weight}` tuples. For unweighted graphs, use weight 1.

## Examples

    iex> # Unweighted adjacency list
    ...> entries = [
    ...>   {1, [{2, 1}, {3, 1}]},
    ...>   {2, [{3, 1}]},
    ...>   {3, []}
    ...> ]
    iex> graph = Yog.IO.List.from_list(:undirected, entries)
    iex> Yog.Model.order(graph)
    3
    iex> Yog.Model.edge_count(graph)
    3

    iex> # Weighted adjacency list
    ...> weighted = [
    ...>   {1, [{2, 5}, {3, 10}]},
    ...>   {2, [{3, 2}]},
    ...>   {3, []}
    ...> ]
    iex> digraph = Yog.IO.List.from_list(:directed, weighted)
    iex> Yog.Model.edge_count(digraph)
    3

## Notes

- For undirected graphs, edges are added in both directions automatically
- Nodes with empty neighbor lists are still added to the graph
- Duplicate edges are handled by the underlying graph structure

# `from_string`

```elixir
@spec from_string(:directed | :undirected, String.t(), keyword()) :: Yog.graph()
```

Creates a graph from a string representation of an adjacency list.

Parses a string in the format:

```
node_id: neighbor1 neighbor2...
```

## Parameters

- `type` - `:directed` or `:undirected`
- `string` - Multiline string with adjacency list format
- `opts` - Options:
  - `:weighted` - `true` to parse weighted edges (format: "neighbor,weight")
  - `:delimiter` - Delimiter between node and neighbors (default: ":")

## Examples

    iex> text = """
    ...> 1: 2 3
    ...> 2: 3
    ...> 3:
    ...> """
    iex> graph = Yog.IO.List.from_string(:undirected, text)
    iex> Yog.Model.order(graph)
    3

    iex> # Weighted format
    iex> weighted_text = """
    ...> 1: 2,5 3,10
    ...> 2: 3,2
    ...> """
    iex> graph = Yog.IO.List.from_string(:directed, weighted_text, weighted: true)
    iex> Yog.Model.edge_count(graph)
    3

# `to_list`

```elixir
@spec to_list(Yog.graph()) :: [adjacency_entry()]
```

Exports a graph to an adjacency list representation.

Returns a list of `{node_id, neighbors}` tuples where neighbors is a list
of `{neighbor_id, weight}` tuples.

## Examples

    iex> graph = Yog.undirected()
    ...>   |> Yog.add_node(1, nil)
    ...>   |> Yog.add_node(2, nil)
    ...>   |> Yog.add_node(3, nil)
    ...>   |> Yog.add_edge_ensure(from: 1, to: 2, with: 5)
    ...>   |> Yog.add_edge_ensure(from: 2, to: 3, with: 7)
    iex> entries = Yog.IO.List.to_list(graph)
    iex> entries
    [{1, [{2, 5}]}, {2, [{1, 5}, {3, 7}]}, {3, [{2, 7}]}]

## Notes

- Node order is deterministic (sorted by node ID)
- For undirected graphs, each edge appears twice (once for each direction)
- Isolated nodes have empty neighbor lists

# `to_string`

```elixir
@spec to_string(
  Yog.graph(),
  keyword()
) :: String.t()
```

Exports a graph to a string representation of an adjacency list.

## Options

- `weighted` - `true` to include weights (format: "neighbor,weight")
- `delimiter` - Delimiter between node and neighbors (default: ":")
- `node_formatter` - Function to convert node IDs to strings (default: `&Kernel.to_string/1`)
- `weight_formatter` - Function to convert edge weights to strings (default: `&Yog.Utils.to_weight_label/1`)

## Examples

    iex> graph = Yog.undirected()
    ...>   |> Yog.add_edge_ensure(from: 1, to: 2, with: 5)
    ...>   |> Yog.add_edge_ensure(from: 2, to: 3, with: 7)
    iex> Yog.IO.List.to_string(graph)
    "1: 2\n2: 1 3\n3: 2"

    iex> # Using custom formatters for complex types
    iex> graph = Yog.undirected()
    ...>   |> Yog.add_edge_with({1, 2}, {3, 4}, [weight: 10], & &1)
    iex> Yog.IO.List.to_string(graph,
    ...>   node_formatter: fn {a, b} -> "#{a}_#{b}" end,
    ...>   weight_formatter: fn [weight: w] -> "w#{w}" end,
    ...>   weighted: true
    ...> )
    "1_2: 3_4,w10\n3_4: 1_2,w10"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
