Two (and higher-level) arrays in Odin - Beginner Q

To repeat, this is very much a beginner’s question.

What is the standard way to declare and modify a fixed-length, multi-dimensional array in Odin? Ideally, I am looking for something as ergonomic as C’s “my_2d_array[5][5] = my_value”, but I’ll take whatever Odin requires.

When I’ve done that, my next quests for docs and/or examples will be along the same lines, but for 3D arrays, and dynamic-length 2D and 3D arrays.

So far, I’ve looked at Overview | Odin Programming Language, and GitHub - odin-lang/examples: Examples of idiomatic Odin code. I was surprised to see no mention of multi-dimensional arrays in the former, and am quite sure I’m missing something obvious in the latter. Would you be very kind and point me in the right direction?

Respectfully yours,
Alexander

There is this:
array-basics-swizzling-and-array-programming
The awesomeness of this book cannot be overstated:
https://odinbook.com/

The following should hopefully get you started. Note that core:fmt is your Odin friend. You can print anything to see what it “looks” like.

package array_demo

import "core:fmt"

main :: proc() {

	num := 42
	array_auto_assign_all: [4]int
	array_auto_assign_all = num
	fmt.println(array_auto_assign_all)

	array_auto_assign_some: [4]int
	array_auto_assign_some.xy = num
	fmt.println(array_auto_assign_some)

	implied_fixed1 := []int {1, 2, 3, 4}
	implied_fixed2 := [][]int{
		{1, 2, 3, 4},
		{1, 2, 3, 4},
		{1, 2, 3, 4},
		{1, 2, 3, 4},
	}

	fmt.println(implied_fixed1)
	fmt.println(implied_fixed2)

	fixed_size1 := [4]int {1, 2, 3, 4}
	fixed_size2 := [4][4]int{
		{1, 2, 3, 4},
		{1, 2, 3, 4},
		{1, 2, 3, 4},
		{1, 2, 3, 4},
	}

	fmt.println(fixed_size1)
	fmt.println(fixed_size2)

	fixed_size3d := [4][4][4]int{
		{{1, 2, 3, 4 },	{ 1, 2, 3, 4 }, {1, 2, 3, 4 },	{1, 2, 3, 4 }},
		{{1, 2, 3, 4 },	{ 1, 2, 3, 4 }, {1, 2, 3, 4 },	{1, 2, 3, 4 }},
		{{1, 2, 3, 4 },	{ 1, 2, 3, 4 }, {1, 2, 3, 4 },	{1, 2, 3, 4 }},
		{{1, 2, 3, 4 },	{ 1, 2, 3, 4 }, {1, 2, 3, 4 },	{1, 2, 3, 4 }},
	}
	fmt.println(fixed_size3d)

	// number after colon is exclusive, i.e. that index is not included
	first3_slice := fixed_size1[:3]
	fmt.println(first3_slice)
	// Only 1 row, 3 is exclusive
	row2_slice := fixed_size1[2:3]
	fmt.println(row2_slice)

	//predefined element aliases
	is_same: bool
	is_same = fixed_size1.x == fixed_size1.r
	is_same = fixed_size1.y == fixed_size1.g
	is_same = fixed_size1.z == fixed_size1.b
	is_same = fixed_size1.w == fixed_size1.a
	//	%v is for any variable type
	//  # will print it's natural form
	//	https://pkg.odin-lang.org/core/fmt/
	fmt.printfln("%#v", is_same)

	swizzle_flip := fixed_size1.zyx
	fmt.println(swizzle_flip)

	array_math := fixed_size1 + 42
	fmt.println(array_math)

	array_math = fixed_size1 + fixed_size2[1]
	fmt.println(array_math)

	// loop 1 dimension
	for i in fixed_size1 {
		fmt.println(i)
	}

	// loop 2 dimension
	for i in fixed_size2 {
		for j in i {
			fmt.print(j)
		}
		fmt.println()
	}

	dyn_no_starting_size := make([dynamic]int)
	append(&dyn_no_starting_size, 1)
	append(&dyn_no_starting_size, 2)
	append(&dyn_no_starting_size, 3)
	append(&dyn_no_starting_size, 4)
	fmt.println(dyn_no_starting_size)
	delete(dyn_no_starting_size)

	dyn_starting_size4 := make([dynamic]int, 4)
	dyn_starting_size4[0] = 1
	dyn_starting_size4[1] = 2
	dyn_starting_size4[2] = 3
	dyn_starting_size4[3] = 4
	append(&dyn_starting_size4, 5)
	append(&dyn_starting_size4, 6)
	append(&dyn_starting_size4, 7)
	append(&dyn_starting_size4, 8)
	fmt.println(dyn_starting_size4)
	delete(dyn_starting_size4)


	dyn_safety := make([dynamic]int, 4)
	//	defer delete to end of scope
	defer delete(dyn_safety)

	for i in 0..<8 {
		if i > len(dyn_safety) - 1 {
			append(&dyn_safety, i)
		} else {
			dyn_safety[i] = i + 1
		}
	}
	fmt.println(dyn_safety)

	dyn_multi :=make([dynamic][4]int)
	append(&dyn_multi, [4]int{1,2,3,4})

	my_num_set := [4]int{1,2,3,4}
	append(&dyn_multi, my_num_set)

	// mulitply 4 since this is 2d array of [dynamic][4]
	if cap(dyn_multi) == 4 * len(dyn_multi) {
		append(&dyn_multi, my_num_set)
	} else {
		dyn_multi[2] = my_num_set
	}

	delete(dyn_multi)
}
2 Likes

Some more idiomatic examples. Mostly because I’m a dork, and also just in case I didn’t answer your question.

package array_demo

import "core:fmt"

main :: proc() {

{
	array1d: [4]int
	array1d = {1,2,3,4}

	array2d: [4][4]int
	array2d = {array1d, array1d, array1d, array1d}

	fmt.printfln("%v", array2d)

	// some swizzling
	array2d[0] = array1d.wzyx
	array2d[1] = array1d.xxxx
	array2d[2] = array1d.yyyy
	array2d[3] = array1d.wwzz

	fmt.printfln("%v", array2d)

	array1d = array2d.x
	fmt.printfln("%v", array1d)

	array1d = array2d[0].xzxz
	fmt.printfln("%v", array1d)
}

{
	array1_2d := [4][4]int{1,2,3,4} // these [4] will be asigned to all [4][4]
	array2_2d := [4][4]int{1,2,3,4} // these [4] will be asigned to all [4][4]
	array3_2d:   [4][4]int

	array3_2d = array1_2d * array2_2d
	fmt.printfln("%v", array3_2d)

	array4_2d := array3_2d
	array3_2d *= 84
	array3_2d /= 2 * array4_2d
	// use %w to see Odin syntax version of output
	fmt.printfln("%w", array3_2d)
	// human readable way
	for i in array3_2d {
		fmt.printfln("%w", i.xyzw)
	}
	// or
	for &i in array3_2d {
		fmt.printfln("%w", i[:])
	}
}

}

The best way to create a dynamic multi-dimensional array is to allocate a slice for all the items (so widthheightdepth in 3D) and then use a small procedure to convert 3D coordinates into a 1D index.
This is significantly better than allocating each row dynamically separately.

1 Like

Thank you, xuul, for your detailed response! :slightly_smiling_face: It took a bit for me to understand it, but it’s been most helpful.
Point well taken, jakubtomsu.

I can provide more details for anything in the examples provided if there is a need for more clarity. Feel free to point out anything specific. I’m always willing to help others get a better understanding of and addiction to Odin.