How to flatten a 2D slice into 1D slice? - go

I have
arr := [][]int32 {{1,2,3} ,{4,5,6}, {7,8,9}}
and I want
newArr := []int32 {1,2,3,4,5,6,7,8,9}
In JS I can do
arr1d = [].concat(...arr2d);
as one of many simple ways like this
Is there in Go something like this?

Go has strings.Join and bytes.Join, but no generic functionality to join/concat a slice. It's possible that once generics are introduced into the language such functionality will be added to the standard library.
In the meantime, doing this with a loop is clear and concise enough.
var newArr []int32
for _, a := range arr {
newArr = append(newArr, a...)
}

Go 1.18
You can't avoid a for loop, but with generics this is easily extensible to slices of any type:
func Flatten[T any](lists [][]T) []T {
var res []T
for _, list := range lists {
res = append(res, list...)
}
return res
}
Example usage:
func main() {
w := [][]string{{"a", "b", "c"}, {"d", "e", "f"}}
v := Flatten(w)
fmt.Println(v) // [a b c d e f]
d := [][]uint64{{100, 200}, {3000, 4000}}
e := Flatten(d)
fmt.Println(e) // [100 200 3000 4000]
}
Playground: https://go.dev/play/p/X81g7GYFd4n

Related

Code to generate powerset in Golang gives wrong result

Next code in Golang to generate powerset produces wrong result on input {"A", "B", "C", "D", "E"}. I see [A B C E E] as the last generated set.
package main
import (
"fmt"
)
func main() {
for _, s := range PowerSet([]string{"A", "B", "C", "D", "E"}) {
fmt.Println(s)
}
}
func PowerSet(set []string) [][]string {
var powerSet [][]string
powerSet = append(powerSet, make([]string, 0))
for _, element := range set {
var moreSets [][]string
for _, existingSet := range powerSet {
newSet := append(existingSet, element)
moreSets = append(moreSets, newSet)
}
powerSet = append(powerSet, moreSets...)
}
return powerSet
}
How to fix it? How to write it idiomatically in Go?
The problem with your program is not the algorithm itself but this line:
newSet := append(existingSet, element)
You should not append and assign to a different variable.
As the documentation states (emphasis mine), "The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated.".
So, there might be cases where newSet := append(existingSet, element) will actually modify existingSet itself, which would break your logic.
If you change that to instead create a new array and append to that one, it works as you expect it.
newSet := make([]string, 0)
newSet = append(newSet, existingSet...)
newSet = append(newSet, element)
For instance, you can use algorithm like this one: https://stackoverflow.com/a/2779467/3805062.
func PowerSet(original []string) [][]string {
powerSetSize := int(math.Pow(2, float64(len(original))))
result := make([][]string, 0, powerSetSize)
var index int
for index < powerSetSize {
var subSet []string
for j, elem := range original {
if index& (1 << uint(j)) > 0 {
subSet = append(subSet, elem)
}
}
result = append(result, subSet)
index++
}
return result
}
Elaborating on #eugenioy's answer.
Look at this thread. Here is a working example : https://play.golang.org/p/dzoTk1kimf
func copy_and_append_string(slice []string, elem string) []string {
// wrong: return append(slice, elem)
return append(append([]string(nil), slice...), elem)
}
func PowerSet(s []string) [][]string {
if s == nil {
return nil
}
r := [][]string{[]string{}}
for _, es := range s {
var u [][]string
for _, er := range r {
u = append(u, copy_and_append_string(er, es))
}
r = append(r, u...)
}
return r
}

Simple mapReduce operation on strings

I have a list of strings
elems := [n]string{...}
I want to perform a simple mapReduce operation, such that I
Map every string to a different string, let's say string -> $string
Reduce all the strings to one string with a separator, e.g. {s1, s2, s3} -> s1#s2#s3
all in all: {s1, s2, s3} -> $s1#$s2#$s3
What's the best way to do this?
I'm looking for efficiency and readability
Bonus points if it's generic enough to work not only on strings
For mapping just a list, you won't have much choice other than to go over each string. If the transform algo is time-consuming and you need speed, you can consider splitting the job and use a go routine. Finally you can use the strings.Join function which has an option to specify a separator, this normally performs the reduce part efficiently. The size of the dataset can also be a consideration, and for larger sized lists you may want to compare performance with strings.Join and your own customized algo and see if you want to use multiple go routines/channels to achieve what you want to.
If you don't need to do the 2 things separately, the end result can be achieved simply by using strings.Join():
package main
import (
"fmt"
"strings"
)
func main() {
a := []string{"a", "b", "c"}
p := "$"
fmt.Println(p + strings.Join(a[:], "#"+p))
}
prints $a#$b#$c
playground
Go is explicitly NOT a functional programming language.
You map and reduce using a for loop.
a := []string{"a", "b", "c"}
result := "initvalue"
for n, i := range a {
result += i + string(n)
}
If you are not going to perform any sort of IO operations inside your map functions (means they are doing just some computations), making it concurrent would make it slower for sure and even if you are doing some IO, you should benchmark. Concurrency would not make things faster necessarily and some times add unnecessary complications. In many cases just a simple for loop is sufficient.
If the map functions here are IO bound or are doing some sort of computation heavy calculations that do benefit from going concurrent, solutions can vary. For example NATS can be used to go beyond one machine and distribute the workload.
This is a relatively simple sample. Reduce phase is not multistage and is blocking:
import (
"fmt"
"strings"
"sync"
"testing"
"github.com/stretchr/testify/assert"
)
type elem struct {
index int
value interface{}
}
func feed(elems []interface{}) <-chan elem {
result := make(chan elem)
go func() {
for k, v := range elems {
e := elem{
index: k,
value: v,
}
result <- e
}
close(result)
}()
return result
}
func mapf(
input <-chan elem,
mapFunc func(elem) elem) <-chan elem {
result := make(chan elem)
go func() {
for e := range input {
eres := mapFunc(e)
result <- eres
}
close(result)
}()
return result
}
// is blocking
func reducef(
input <-chan elem,
reduceFunc func([]interface{}) interface{}) interface{} {
buffer := make(map[int]interface{})
l := 0
for v := range input {
buffer[v.index] = v.value
if v.index > l {
l = v.index
}
}
data := make([]interface{}, l+1)
for k, v := range buffer {
data[k] = v
}
return reduceFunc(data)
}
func fanOutIn(
elemFeed <-chan elem,
mapFunc func(elem) elem, mapCount int,
reduceFunc func([]interface{}) interface{}) interface{} {
MR := make(chan elem)
wg := &sync.WaitGroup{}
for i := 0; i < mapCount; i++ {
mapResult := mapf(elemFeed, mapFunc)
wg.Add(1)
go func() {
defer wg.Done()
for v := range mapResult {
MR <- v
}
}()
}
go func() {
wg.Wait()
close(MR)
}()
return reducef(MR, reduceFunc)
}
func Test01(t *testing.T) {
elemFeed := feed([]interface{}{1, 2, 3})
finalResult := fanOutIn(
elemFeed,
func(e elem) elem {
return elem{
index: e.index,
value: fmt.Sprintf("[%v]", e.value),
}
},
3,
func(sl []interface{}) interface{} {
strRes := make([]string, len(sl))
for k, v := range sl {
strRes[k] = v.(string)
}
return strings.Join(strRes, ":")
})
assert.Equal(t, "[1]:[2]:[3]", finalResult)
}
And since it uses interface{} as the element type, it can get generalized.

How to get intersection of two slice in golang?

Is there any efficient way to get intersection of two slices in Go?
I want to avoid nested for loop like solution
slice1 := []string{"foo", "bar","hello"}
slice2 := []string{"foo", "bar"}
intersection(slice1, slice2)
=> ["foo", "bar"]
order of string does not matter
How do I get the intersection between two arrays as a new array?
Simple Intersection: Compare each element in A to each in B (O(n^2))
Hash Intersection: Put them into a hash table (O(n))
Sorted Intersection: Sort A and do an optimized intersection (O(n*log(n)))
All of which are implemented here
https://github.com/juliangruber/go-intersect
simple, generic and mutiple slices ! (Go 1.18)
Time Complexity : may be linear
func interSection[T constraints.Ordered](pS ...[]T) []T {
hash := make(map[T]*int) // value, counter
result := make([]T, 0)
for _, slice := range pS {
duplicationHash := make(map[T]bool) // duplication checking for individual slice
for _, value := range slice {
if _, isDup := duplicationHash[value]; !isDup { // is not duplicated in slice
if counter := hash[value]; counter != nil { // is found in hash counter map
if *counter++; *counter >= len(pS) { // is found in every slice
result = append(result, value)
}
} else { // not found in hash counter map
i := 1
hash[value] = &i
}
duplicationHash[value] = true
}
}
}
return result
}
func main() {
slice1 := []string{"foo", "bar", "hello"}
slice2 := []string{"foo", "bar"}
fmt.Println(interSection(slice1, slice2))
// [foo bar]
ints1 := []int{1, 2, 3, 9, 8}
ints2 := []int{10, 4, 2, 4, 8, 9} // have duplicated values
ints3 := []int{2, 4, 8, 1}
fmt.Println(interSection(ints1, ints2, ints3))
// [2 8]
}
playground : https://go.dev/play/p/lE79D0kOznZ
It's a best method for intersection two slice. Time complexity is too low.
Time Complexity : O(m+n)
m = length of first slice.
n = length of second slice.
func intersection(s1, s2 []string) (inter []string) {
hash := make(map[string]bool)
for _, e := range s1 {
hash[e] = true
}
for _, e := range s2 {
// If elements present in the hashmap then append intersection list.
if hash[e] {
inter = append(inter, e)
}
}
//Remove dups from slice.
inter = removeDups(inter)
return
}
//Remove dups from slice.
func removeDups(elements []string)(nodups []string) {
encountered := make(map[string]bool)
for _, element := range elements {
if !encountered[element] {
nodups = append(nodups, element)
encountered[element] = true
}
}
return
}
if there exists no blank in your []string, maybe you need this simple code:
func filter(src []string) (res []string) {
for _, s := range src {
newStr := strings.Join(res, " ")
if !strings.Contains(newStr, s) {
res = append(res, s)
}
}
return
}
func intersections(section1, section2 []string) (intersection []string) {
str1 := strings.Join(filter(section1), " ")
for _, s := range filter(section2) {
if strings.Contains(str1, s) {
intersection = append(intersection, s)
}
}
return
}
Try it
https://go.dev/play/p/eGGcyIlZD6y
first := []string{"one", "two", "three", "four"}
second := []string{"two", "four"}
result := intersection(first, second) // or intersection(second, first)
func intersection(first, second []string) []string {
out := []string{}
bucket := map[string]bool{}
for _, i := range first {
for _, j := range second {
if i == j && !bucket[i] {
out = append(out, i)
bucket[i] = true
}
}
}
return out
}
https://github.com/viant/toolbox/blob/a46fd679bbc5d07294b1d1b646aeacd44e2c7d50/collections.go#L869-L920
Another O(m+n) Time Complexity solution that uses a hashmap.
It has two differences compared to the other solutions discussed here.
Passing the target slice as a parameter instead of new slice returned
Faster to use for commonly used types like string/int instead of reflection for all
Yes there are a few different ways to go about it.. Here's an example that can be optimized.
package main
import "fmt"
func intersection(a []string, b []string) (inter []string) {
// interacting on the smallest list first can potentailly be faster...but not by much, worse case is the same
low, high := a, b
if len(a) > len(b) {
low = b
high = a
}
done := false
for i, l := range low {
for j, h := range high {
// get future index values
f1 := i + 1
f2 := j + 1
if l == h {
inter = append(inter, h)
if f1 < len(low) && f2 < len(high) {
// if the future values aren't the same then that's the end of the intersection
if low[f1] != high[f2] {
done = true
}
}
// we don't want to interate on the entire list everytime, so remove the parts we already looped on will make it faster each pass
high = high[:j+copy(high[j:], high[j+1:])]
break
}
}
// nothing in the future so we are done
if done {
break
}
}
return
}
func main() {
slice1 := []string{"foo", "bar", "hello", "bar"}
slice2 := []string{"foo", "bar"}
fmt.Printf("%+v\n", intersection(slice1, slice2))
}
Now the intersection method defined above will only operate on slices of strings, like your example.. You can in theory create a definition that looks like this func intersection(a []interface, b []interface) (inter []interface), however you would be relying on reflection and type casting so that you can compare, which will add latency and make your code harder to read. It's probably easier to maintain and read to write a separate function for each type you care about.
func intersectionString(a []string, b []string) (inter []string),
func intersectionInt(a []int, b []int) (inter []int),
func intersectionFloat64(a []Float64, b []Float64) (inter []Float64), ..ect
You can then create your own package and reuse once you settle how you want to implement it.
package intersection
func String(a []string, b []string) (inter []string)
func Int(a []int, b []int) (inter []int)
func Float64(a []Float64, b []Float64) (inter []Float64)

How to XOR two string arrays in Golang?

Let's say I have two string array.
A = [ "ab", "cd", "ef", "gh"]
B = [ "ef", "gh"]
I want to do C = A^B
where C = ["ab", "cd"]
I'm aware Golang allows XOR byte-wise, but I haven't seen anything for string arrays in the documentation.
How would I go about doing this? Perhaps there is a utility someone has already made for this?
This doesn't seem like something that would go in a standard library in Go, but here's a bit of code that does the trick:
package main
import (
"fmt"
)
func main() {
A := []string{"ab", "cd", "ef", "gh"}
B := []string{"ef", "gh"}
fmt.Println(xor(A,B))
}
func xor(list1, list2 []string) []string {
set1 := make(map[string]bool)
for _, s := range list1 {
set1[s] = true
}
set2 := make(map[string]bool)
for _, s := range list2 {
set2[s] = true
}
var c []string
for _, s := range list1 {
if !set2[s] {
c = append(c, s)
}
}
for _, s := range list2 {
if !set1[s] {
c = append(c, s)
}
}
return c
}
https://play.golang.org/p/SDPhNIQ66E

Short way to apply a function to all elements in a list in golang

Suppose I would like to apply a function to every element in a list, and then put the resulting values in another list so I can immediately use them. In python, I would do something like this:
list = [1,2,3]
str = ', '.join(multiply(x, 2) for x in list)
In Go, I do something like this:
list := []int{1,2,3}
list2 := []int
for _,x := range list {
list2 := append(list2, multiply(x, 2))
}
str := strings.Join(list2, ", ")
Is it possible to do this in a shorter way?
I would do exactly as you did, with a few tweaks to fix typos
import (
"fmt"
"strconv"
"strings"
)
func main() {
list := []int{1,2,3}
var list2 []string
for _, x := range list {
list2 = append(list2, strconv.Itoa(x * 2)) // note the = instead of :=
}
str := strings.Join(list2, ", ")
fmt.Println(str)
}
This is an old question, but was the top hit in my Google search, and I found information that I believe will be helpful to the OP and anyone else who arrives here, looking for the same thing.
There is a shorter way, although you have to write the map function yourself.
In go, func is a type, which allows you to write a function that accepts as input the subject slice and a function, and which iterates over that slice, applying that function.
See the Map function near the bottom of this Go by Example page : https://gobyexample.com/collection-functions
I've included it here for reference:
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
You then call it like so:
fmt.Println(Map(strs, strings.ToUpper))
So, yes: The shorter way you are looking for exists, although it is not built into the language itself.
I've created a small utility package with Mapand Filter methods now that generics have been introduced in 1.18 :)
https://pkg.go.dev/github.com/sa-/slicefunk
Example usage
package main
import (
"fmt"
sf "github.com/sa-/slicefunk"
)
func main() {
original := []int{1, 2, 3, 4, 5}
newArray := sf.Map(original, func(item int) int { return item + 1 })
newArray = sf.Map(newArray, func(item int) int { return item * 3 })
newArray = sf.Filter(newArray, func(item int) bool { return item%2 == 0 })
fmt.Println(newArray)
}
With go1.18+ you can write a much cleaner generic Map function:
func Map[T, V any](ts []T, fn func(T) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
result[i] = fn(t)
}
return result
}
Usage, e.g:
input := []int{4, 5, 3}
outputInts := Map(input, func(item int) int { return item + 1 })
outputStrings := Map(input, func(item int) string { return fmt.Sprintf("Item:%d", item) })
Found a way to define a generic map array function
func Map(t interface{}, f func(interface{}) interface{} ) []interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
s := reflect.ValueOf(t)
arr := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
arr[i] = f(s.Index(i).Interface())
}
return arr
}
return nil
}
origin := []int{4,5,3}
newArray := Map(origin, func(item interface{}) interface{} { return item.(int) + 1})
You can use lo's Map in order to quickly apply a function to all elements. For example, in order to multiply by 2 and convert to string, you can use:
l := lo.Map[int, string]([]int{1, 2, 3, 4}, func(x int, _ int) string { return strconv.Itoa(x * 2) })
Then you can convert back to a comma delimited string like so:
strings.Join(l, ",")

Resources