Skip to content

Commit

Permalink
Improve document
Browse files Browse the repository at this point in the history
  • Loading branch information
taiansu committed Dec 10, 2024
1 parent e2a4167 commit 20bfccd
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 31 deletions.
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,22 @@ of nesting. Each level must maintain consistent structure:

#### 2-dimensional list (matrix)
```elixir
[[1, 2, 3],
[4, 5, 6]]
[
[1, 2, 3],
[4, 5, 6]
]
```

#### 3-dimensional list (cube)
```elixir
[[[1, 2], [3, 4]],
[[5, 6], [7, 8]]]
[
[
[1, 2], [3, 4]
],
[
[5, 6], [7, 8]
]
]
```

### Coordinate Map
Expand Down Expand Up @@ -81,6 +89,14 @@ iex> Ndim.d2map(numbers, fn x -> x * 2 end)
[[2, 4], [6, 8]]
```

Map a function over a n-dimensional list, with specified dimension, which is `3`
```elixir
iex> nested = [[["a", "b"], ["c", "d"]], [["e", "f"], ["g", "h"]], [["i", "j"], ["k", "l"]]]
iex> Ndim.dmap(nested, 3, &String.upcase/1)
[[["A", "B"], ["C", "D"]], [["E", "F"], ["G", "H"]], [["I", "J"], ["K", "L"]]]
```


Transform a 2-dimensional list to a coordinate map
```elixir
iex> vector = [[1, 2], [3, 4]]
Expand Down
89 changes: 62 additions & 27 deletions lib/ndim.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ defmodule Ndim do
The `Ndim` lib provides functions for working with n-dimensional lists.
This module is particularly useful when you need to:
* Map functions over deeply nested lists at a specific level while maintaining their shape
* Transform between the n-dimensional list and the coordinated map
* Map functions over deeply nested lists at a specific level while maintaining their shape
* Transform between the n-dimensional list and the coordinated map
## Terminology
Expand All @@ -13,20 +13,31 @@ defmodule Ndim do
of nesting. Each level must maintain consistent structure:
# 1-dimensional list (vector)
```elixir
[1, 2, 3]
```
# 2-dimensional list (matrix)
```elixir
[[1, 2, 3],
[4, 5, 6]]
[
[1, 2, 3],
[4, 5, 6]
]
```
# 3-dimensional list (cube)
```elixir
[[[1, 2], [3, 4]],
[[5, 6], [7, 8]]]
[
[
[1, 2], [3, 4]
],
[
[5, 6], [7, 8]
]
]
```
### Coordinate map
Expand All @@ -35,6 +46,7 @@ defmodule Ndim do
you need direct coordinate access:
#### From 2-dimensional list to 2d coordinate map
```elixir
[
[1, 2], --> %{{0, 0} => 1, {0, 1} => 2,
Expand All @@ -43,6 +55,7 @@ defmodule Ndim do
```
#### From 3-dimensional list to 3d coordinate map
```elixir
[
[[1, 2]], --> %{{0, 0, 0} => 1, {0, 0, 1} => 2,
Expand All @@ -52,26 +65,27 @@ defmodule Ndim do
## Core functions
* `d2map/2` ... `d5map/2` - Map a function over a 2-dimensonal list (upto 5)
* `dmap/3` - The general version which maps a function over elements at any specified dimensional list
* `to_coordinate_map/1` - Transform a n-dimensional list to a coordinate map
* `d2map/2` ... `d5map/2` - Map a function over a 2-dimensonal list (upto 5)
* `dmap/3` - The general version which maps a function over elements at any specified dimensional list
* `to_coordinate_map/1` - Transform a n-dimensional list to a coordinate map
## Examples
Map a function over a 2-dimensional list
```elixir
iex> numbers = [[1, 2], [3, 4]]
iex> Ndim.d2map(numbers, fn x -> x * 2 end)
[[2, 4], [6, 8]]
```
```elixir
iex> numbers = [[1, 2], [3, 4]]
iex> Ndim.d2map(numbers, fn x -> x * 2 end)
[[2, 4], [6, 8]]
```
Transform a 2-dimensional list to a coordinate map
```elixir
iex> vector = [[1, 2], [3, 4]]
iex> Ndim.to_coordinate_map(vector)
%{{0, 0} => 1, {0, 1} => 2, {1, 0} => 3, {1, 1} => 4}
```
```elixir
iex> vector = [[1, 2], [3, 4]]
iex> Ndim.to_coordinate_map(vector)
%{{0, 0} => 1, {0, 1} => 2, {1, 0} => 3, {1, 1} => 4}
```
"""

@doc """
Expand All @@ -84,16 +98,16 @@ defmodule Ndim do
* `fun` - The function to apply at the specified dimension
## Examples
```elixir
iex> numbers = [[1, 2], [3, 4], [5, 6]]
iex> Ndim.dmap(numbers, 2, fn i -> i * 10 end)
[[10, 20], [30, 40], [50, 60]]
iex> nested = [[["a", "b"], ["c", "d"]], [["e", "f"], ["g", "h"]], [["i", "j"], ["k", "l"]]]
iex> Ndim.dmap(nested, 3, &String.upcase/1)
[[["A", "B"], ["C", "D"]], [["E", "F"], ["G", "H"]], [["I", "J"], ["K", "L"]]]
```
```elixir
iex> numbers = [[1, 2], [3, 4], [5, 6]]
iex> Ndim.dmap(numbers, 2, fn i -> i * 10 end)
[[10, 20], [30, 40], [50, 60]]
iex> nested = [[["a", "b"], ["c", "d"]], [["e", "f"], ["g", "h"]], [["i", "j"], ["k", "l"]]]
iex> Ndim.dmap(nested, 3, &String.upcase/1)
[[["A", "B"], ["C", "D"]], [["E", "F"], ["G", "H"]], [["I", "J"], ["K", "L"]]]
```
"""
def dmap(list, dim, func) do
dim_accessors = List.duplicate(Access.all(), dim)
Expand All @@ -106,13 +120,16 @@ defmodule Ndim do
This is equivalent to calling `dmap(list, 2, fun)`.
## Examples
```elixir
iex> numbers = [[1, 2], [3, 4], [5, 6]]
iex> Ndim.d2map(numbers, fn x -> x * 2 end)
[[2, 4], [6, 8], [10, 12]]
iex> strings = [["a", "b"], ["c", "d"]]
iex> Ndim.d2map(strings, &String.upcase/1)
[["A", "B"], ["C", "D"]]
```
"""
def d2map(list, fun), do: dmap(list, 2, fun)

Expand All @@ -122,13 +139,16 @@ defmodule Ndim do
This is equivalent to calling `dmap(list, 3, fun)`.
## Examples
```elixir
iex> numbers = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
iex> Ndim.d3map(numbers, fn x -> x + 1 end)
[[[2, 3], [4, 5]], [[6, 7], [8, 9]]]
iex> strings = [[["hello", "world"], ["foo"]], [["bar"], ["baz", "qux"]]]
iex> Ndim.d3map(strings, &String.capitalize/1)
[[["Hello", "World"], ["Foo"]], [["Bar"], ["Baz", "Qux"]]]
```
"""
def d3map(list, fun), do: dmap(list, 3, fun)

Expand All @@ -138,13 +158,16 @@ defmodule Ndim do
This is equivalent to calling `dmap(list, 4, fun)`.
## Examples
```elixir
iex> numbers = [[[[1, 2], [3]], [[4, 5]]], [[[6]], [[7, 8], [9]]]]
iex> Ndim.d4map(numbers, fn x -> x * 2 end)
[[[[2, 4], [6]], [[8, 10]]], [[[12]], [[14, 16], [18]]]]
iex> strings = [[[[{"a", 1}]]], [[[{"b", 2}]]]]
iex> Ndim.d4map(strings, fn {str, num} -> {String.upcase(str), num} end)
[[[[{"A", 1}]]], [[[{"B", 2}]]]]
```
"""
def d4map(list, fun), do: dmap(list, 4, fun)

Expand All @@ -154,13 +177,16 @@ defmodule Ndim do
This is equivalent to calling `dmap(list, 5, fun)`.
## Examples
```elixir
iex> numbers = [[[[[1]], [[2]]], [[[3]]]], [[[[4]]], [[[5]], [[6]]]]]
iex> Ndim.d5map(numbers, fn x -> x + 10 end)
[[[[[11]], [[12]]], [[[13]]]], [[[[14]]], [[[15]], [[16]]]]]
iex> data = [[[[[%{x: 1}]], [[%{x: 2}]]]], [[[[%{x: 3}]]]]]
iex> Ndim.d5map(data, fn map -> Map.update!(map, :x, & &1 * 2) end)
[[[[[%{x: 2}]], [[%{x: 4}]]]], [[[[%{x: 6}]]]]]
```
"""
def d5map(list, fun), do: dmap(list, 5, fun)

Expand All @@ -174,6 +200,8 @@ defmodule Ndim do
* `dimension` - (Optional) The expected dimension of the nested list
## Examples
```elixir
# Automatic dimension detection
iex> matrix = [[1, 2], [3, 4]]
iex> Ndim.to_coordinate_map(matrix)
Expand All @@ -192,6 +220,7 @@ defmodule Ndim do
iex> cube = [[[1, 2]], [[3, 4]]]
iex> Ndim.to_coordinate_map(cube, 3)
%{{0, 0, 0} => 1, {0, 0, 1} => 2, {1, 0, 0} => 3, {1, 0, 1} => 4}
```
## Return Value
Returns a map where keys are tuples of coordinates and values are the corresponding
Expand Down Expand Up @@ -266,6 +295,8 @@ defmodule Ndim do
nested structures where elements at the same depth share the same dimensionality.
## Examples
```elixir
iex> Ndim.get_depth([])
0
Expand All @@ -277,13 +308,17 @@ defmodule Ndim do
iex> Ndim.get_depth([[[1, 2]], [[3, 4]]])
3
```
## Error cases
```elixir
iex> Ndim.get_depth([1, [2, 3]])
** (ArgumentError) list is not a regular nested structure
iex> Ndim.get_depth([[1, 2], [3]])
** (ArgumentError) list is not a regular nested structure
```
## Return Value
Returns an integer representing the depth (dimension) of the nested list.
Expand Down
8 changes: 8 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
%{
"earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"},
"ex_doc": {:hex, :ex_doc, "0.35.1", "de804c590d3df2d9d5b8aec77d758b00c814b356119b3d4455e4b8a8687aecaf", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "2121c6402c8d44b05622677b761371a759143b958c6c19f6558ff64d0aed40df"},
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
"makeup_elixir": {:hex, :makeup_elixir, "1.0.0", "74bb8348c9b3a51d5c589bf5aebb0466a84b33274150e3b6ece1da45584afc82", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "49159b7d7d999e836bedaf09dcf35ca18b312230cf901b725a64f3f42e407983"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
}

0 comments on commit 20bfccd

Please sign in to comment.