Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to implement the python `zip` function in golang?

Tags:

Sometimes, it's convenient to combine two lists into a tuple using zip built-in function in Python. How to make this similarly in Go?

For example:

>>> zip ([1,2],[3,4])
[(1,3), (2,4)]
like image 879
holys Avatar asked Nov 16 '14 12:11

holys


People also ask

What is zip () function in tuple give an example program using zip () function?

The zip() function returns an iterator of tuples based on the iterable objects. If a single iterable is passed, zip() returns an iterator of tuples with each tuple having only one element. If multiple iterables are passed, zip() returns an iterator of tuples with each tuple having elements from all the iterables.

How zip function works in Python?

The zip() function returns a zip object, which is an iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together etc.

How do you print a zip object in Python?

If you want to include unmatched characters from the other two strings in the zipped object, use zip_longest() function defined in itertools module. Instead of None , any other character can be specified as fillvalue parameter. print(list(itertools.

How do you zip a dictionary in Python?

Python's zip() function is defined as zip(*iterables) . The function takes in iterables as arguments and returns an iterator. This iterator generates a series of tuples containing elements from each iterable. zip() can accept any type of iterable, such as files, lists, tuples, dictionaries, sets, and so on.


2 Answers

You could do something like this, where you give the tuple type a name:

package main

import "fmt"

type intTuple struct {
    a, b int
}

func zip(a, b []int) ([]intTuple, error) {

    if len(a) != len(b) {
        return nil, fmt.Errorf("zip: arguments must be of same length")
    }

    r := make([]intTuple, len(a), len(a))

    for i, e := range a {
        r[i] = intTuple{e, b[i]}
    }

    return r, nil
}

func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    b := []int{0, 9, 8, 7, 6, 5, 4, 3, 2, 1}
    fmt.Println(zip(a, b))
}

Or alternatively use an unnamed type for the tuple, like this:

package main

import "fmt"

func zip(a, b []int) ([][3]int, error) {

    if len(a) != len(b) {
        return nil, fmt.Errorf("zip: arguments must be of same length")
    }

    r := make([][4]int, len(a), len(a))

    for i, e := range a {
        r[i] = [2]int{e, b[i]}
    }

    return r, nil
}

func main() {
    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    b := []int{0, 9, 8, 7, 6, 5, 4, 3, 2, 1}
    fmt.Println(zip(a, b))
}

And finally here's a soft-generic way of doing it:

package main

import (
    "fmt"
    "reflect"
)

func zip(a, b, c interface{}) error {

    ta, tb, tc := reflect.TypeOf(a), reflect.TypeOf(b), reflect.TypeOf(c)

    if ta.Kind() != reflect.Slice || tb.Kind() != reflect.Slice || ta != tb {
        return fmt.Errorf("zip: first two arguments must be slices of the same type")
    }

    if tc.Kind() != reflect.Ptr {
        return fmt.Errorf("zip: third argument must be pointer to slice")
    }

    for tc.Kind() == reflect.Ptr {
        tc = tc.Elem()
    }

    if tc.Kind() != reflect.Slice {
        return fmt.Errorf("zip: third argument must be pointer to slice")
    }

    eta, _, etc := ta.Elem(), tb.Elem(), tc.Elem()

    if etc.Kind() != reflect.Array || etc.Len() != 2 {
        return fmt.Errorf("zip: third argument's elements must be an array of length 2")
    }

    if etc.Elem() != eta {
        return fmt.Errorf("zip: third argument's elements must be an array of elements of the same type that the first two arguments are slices of")
    }

    va, vb, vc := reflect.ValueOf(a), reflect.ValueOf(b), reflect.ValueOf(c)

    for vc.Kind() == reflect.Ptr {
        vc = vc.Elem()
    }

    if va.Len() != vb.Len() {
        return fmt.Errorf("zip: first two arguments must have same length")
    }

    for i := 0; i < va.Len(); i++ {
        ea, eb := va.Index(i), vb.Index(i)
        tt := reflect.New(etc).Elem()
        tt.Index(0).Set(ea)
        tt.Index(1).Set(eb)
        vc.Set(reflect.Append(vc, tt))
    }

    return nil
}

func main() {

    a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}
    b := []int{0, 9, 8, 7, 6, 5, 4, 3, 2, 1}
    c := [][2]int{}

    e := zip(a, b, &c)

    if e != nil {
        fmt.Println(e)
        return
    }

    fmt.Println(c)
}
like image 99
thwd Avatar answered Oct 10 '22 09:10

thwd


To zip some number of slice []int lists,

package main

import "fmt"

func zip(lists ...[]int) func() []int {
    zip := make([]int, len(lists))
    i := 0
    return func() []int {
        for j := range lists {
            if i >= len(lists[j]) {
                return nil
            }
            zip[j] = lists[j][i]
        }
        i++
        return zip
    }
}

func main() {
    a := []int{1, 2, 3}
    b := []int{4, 5, 6}
    c := []int{7, 8, 9, 0}
    iter := zip(a, b, c)
    for tuple := iter(); tuple != nil; tuple = iter() {
        fmt.Println("tuple:", tuple)
    }
}

Output:

tuple: [1 4 7]
tuple: [2 5 8]
tuple: [3 6 9]
like image 36
peterSO Avatar answered Oct 10 '22 09:10

peterSO