joining 2 dimensional array by columns - go

I have 2 dimensional array on golang something like
array which contains [1,2,3,4]
[2,3,4,5]
[3,4,5,6]
and I want to join the array columns i.e the result should be
1,2,3
2,3,4
3,4,5
4,5,6
my approach is something like this to create 4 arrays and do something like this:
a := []int{}
for _, row := range array {
append (a,array[1])
append (b,array[2])
append (c,array[2])
append (d,array[2])
}
and then join those arrays something like this
fmt.Println(strings.Join(a[:], ","))
fmt.Println(strings.Join(b[:], ","))
fmt.Println(strings.Join(c[:], ","))
fmt.Println(strings.Join(d[:], ","))
my question if there are an option to access the array by columns not by row or if there are more usful way to do this?

Instead of instantiating multiple arrays, you can just work with another two-dimensional array.
Here's a quick pass at an implementation (it could use more error checking, e.g. assumes all of the inner arrays in the input are the same length):
package main
import (
"fmt"
)
func transpose(input [][]int) [][]int {
result := make([][]int, len(input[0]))
for _, row := range(input) {
for j, value := range(row) {
result[j] = append(result[j], value)
}
}
return result
}
func main() {
input := [][]int{{1,2,3,4}, {2,3,4,5}, {3,4,5,6}}
result := transpose(input)
fmt.Println(input)
fmt.Println(result)
}
Output:
[[1 2 3 4] [2 3 4 5] [3 4 5 6]]
[[1 2 3] [2 3 4] [3 4 5] [4 5 6]]
Go Playground

flatten the list of list to a single list. slice the list into intervals using itemgetter and assemble into a single list.
from operator import itemgetter
data=[[1,2,3,4],[2,3,4,5], [3,4,5,6]]
data = [item for sublist in data for item in sublist]
index=[slice(0,4),slice(4,8),slice(8,13)]
result=[]
for idx_slice in index:
f = itemgetter(idx_slice)
col1=f(data)
result.append(col1)
print(result)
output:
[[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6]]

Related

Difference between copy and assign slice golang

Hi everyone I hope you guys doing well, I was reading the copy build-in function, and I was wondering what was the difference between straight assign value from arr to tmp and copy the value from arr to tmp? since both will have the same result both value and cap and length of arr slice. here's the golang playground.
package main
import "fmt"
func main() {
arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
fmt.Println(tmp)
fmt.Println(arr)
fmt.Println(cap(tmp))
fmt.Println(len(tmp))
tmp2 := arr
fmt.Println(tmp2)
fmt.Println(cap(tmp2))
fmt.Println(len(tmp2))
}
the result is,
[1 2 3]
[1 2 3]
3
3
[1 2 3]
3
3
if they had a difference what will it be and can you explain it with an example, please and thank you for your time and consideration :)
The backing array of tmp is a copy of the the backing array from arr.
The slices tmp2 and arr share the same backing array.
See this code:
arr := []int{1, 2, 3}
tmp := make([]int, len(arr))
copy(tmp, arr)
tmp2 := arr
arr[0] = 22
fmt.Println(arr) // prints [22 2 3]
fmt.Println(tmp) // prints [1 2 3]
fmt.Println(tmp2) // prints [22 2 3]
Notice how changing an element in arr also changed in element in tmp2, but not tmp.
As Muffin already answered, slice data structure is a pointer to an array. So if you assign to a new variable, it is still a pointer to the same array. That's why, any changes you make to the slice is reflected back to the array it represents.
Also, a new slice is initialised with a small capacity (array length). Once it is fully occupied, it has to create a new array and copy all its content from the old to new array.

Why does the keyword range in golang work for 2d-slices?

I'd like to make a copy of a slice of bytes, convert the type from [][4]byte to [][]byte. And I expect the followering code to return [[1 2 3 4] [2 3 4 5]], but actually got [[2 3 4 5] [2 3 4 5]].
package main
import "fmt"
func main() {
ids := [][4]byte{[4]byte{1, 2, 3, 4}, [4]byte{2, 3, 4, 5}}
var slices [][]byte
for _, id := range ids {
slices = append(slices, id[:])
}
fmt.Println(slices)
}
Why?
Why appending id[:] to the slice would overwrite the first element in the slice?
As said by Marc, you are appending a reference via id.
Therefore when you iterate, and id changes its value, your "slices" to which you are appending are getting re-evaluated with id new values.
To avoid this:
for i := range ids {
slices = append(slices, ids[i][:]) // here you are referring to the value at index i of ids
}

The most concise way to concatenate 3 or more slices

I am looking for a way to concisely and efficiently concatenate 3 or more slices in Go.
Let's say I want to concatenate the following slices (all the code can be found here - https://play.golang.org/p/6682YiFF8qG):
a := []int{1, 2, 3}
b := []int{4, 5, 6}
c := []int{7, 8, 9}
My first attempt is by using the append method:
d1 := append(a, b...)
d1 = append(d1, c...) // [1 2 3 4 5 6 7 8 9]
However, this method is verbose and requires 2 append calls for concatenating three slices. So, for n slices, I will need n-1 calls to append, which is not only verbose, but also inefficient as it requires multiple allocations.
My next attempt is to create a variadic function to handle the concatenation with only one new slice allocation:
func concat(slicesOfSlices ...[]int) []int {
var totalLengthOfSlices int
for _, slice := range slicesOfSlices {
totalLengthOfSlices += len(slice)
}
arr := make([]int, 0, totalLengthOfSlices)
for _, slice := range slicesOfSlices {
arr = append(arr, slice...)
}
return arr
}
Then I can use it as follows:
d2 := concat(a, b, c) // [1 2 3 4 5 6 7 8 9]
To illustrate, I want to emulate the following convenient functionality of the spread operator in JavaScript, which I often use in the following way:
const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [7, 8, 9];
const d = [...a, ...b, ...c]; // [1, 2, 3, 4, 5, 6, 7, 8, 9]
In other words, I am looking for a way to do something like d3 := append(a, b, c) or d3 := append(a, b..., c...) but with the standard Go library or using less code than I did.
Note on possible duplicates
I don't think this is a duplicate of the question "How to concatenate two slices" as my question is about concatenating 3 or more slices in the most concise and idiomatic way.
You could use your first method of using append like this:
a := []int{1, 2, 3, 4}
b := []int{9, 8, 7, 6}
c := []int{5, 4, 3, 2}
a = append(a, append(b, c...)...)
That being said, I think that your variadic concat function is cleaner and isn't very much code for a utility function.
(Go Playground Link)
Good luck!

append to a new slice affect original slice

I have the following code which causes a weird result. I cannot understand why:
func main() {
var s = []int{2, 3}
var s1 = append(s, 4)
var a = append(s1, 5)
var b = append(s1, 6)
fmt.Println(s)
fmt.Println(s1)
fmt.Println(a)
fmt.Println(b)
}
This then results in:
[2 3]
[2 3 4]
[2 3 4 6]
[2 3 4 6]
My question is: why a is not [2 3 4 5] but [2 3 4 6]? I know append to b changes a, but how. Is this a bug because I never changed a directly and obviously I don't want this happen?
Keep in mind that a slice is a structure of 3 fields.
a pointer to the underlying array
length of the slice
capacity of the slice
append() function may either modify its argument in-place or return a copy of its argument with an additional entry, depending on the size and capacity of its input. append() function creates a new slice, if the length the slice is greater than the length of the array pointed by the slice.

In Go, how do I duplicate the last element of a slice?

If I have a Python list, it is simple to duplicate the last element: l.append(l[-1]). Is there an elegant way to do this with Go slices?
The best I have so far is data = append(data, data[len(data) - 1]).
That is the proper way to do it.
In Go you can't use negative indices, so the index of the last element is len(data) -1.
And in Go append() is a builtin function and not a method of slices, and it returns a new slice value which you have to assign or store if you need the extended slice, so there's nothing you can make shorter in your code in general.
Note that if you were on to create your own type, you could attach methods to it which could simpify things. For example:
type ints []int
func (i *ints) append(es ...int) {
*i = append(*i, es...)
}
func (i *ints) appendLast() {
*i = append(*i, (*i)[len(*i)-1])
}
Using it:
is := ints{1, 2, 3}
fmt.Println(is)
is.append(4, 5) // Append some elements
fmt.Println(is)
is.append(is[len(is)-1]) // Append last element explicitly
fmt.Println(is)
is.appendLast() // Append last element using appendLast method
fmt.Println(is)
// You can also use it for []int values, with conversion:
is2 := []int{1, 2, 3}
(*ints)(&is2).appendLast()
fmt.Println(is2)
Output (try it on the Go Playground):
[1 2 3]
[1 2 3 4 5]
[1 2 3 4 5 5]
[1 2 3 4 5 5 5]
[1 2 3 3]
You can also use simple util functions without creating a new type:
func appendLast(i []int) []int {
return append(i, i[len(i)-1])
}
func appendLast2(i *[]int) {
*i = append(*i, (*i)[len(*i)-1])
}
func main() {
is := []int{1, 2, 3}
fmt.Println(is)
is = appendLast(is)
fmt.Println(is)
appendLast2(&is)
fmt.Println(is)
}
Output (try it on the Go Playground):
[1 2 3]
[1 2 3 3]
[1 2 3 3 3]
data = append(data, data[len(data) - 1])
Yes. It's the best way to do in Go. It's not possible to use a negative index in Go.

Resources