登录
首页 >  Golang >  Go问答

修改 2D 切片原地

来源:stackoverflow

时间:2024-03-23 15:36:33 233浏览 收藏

在 Go 中实现矩阵乘法算法时,需要修改输出矩阵,但发现 2D 切片无法作为指针传递。这篇文章提供了两种解决方法: 1. 由于切片本身就是引用类型,可以将切片直接传递给函数,函数中对切片内容的修改在调用者中可见。 2. 返回一个新切片,同样也是引用类型,不会占用大量内存,并且修改内容在调用者中可见。

问题内容

我正在 go 中实现矩阵-矩阵乘法算法,但我无法推理如何就地更改输出矩阵。我尝试将输入更改为指针,但 2d 切片不能是指针?

package main

import (
    "fmt"
    "strconv"
    "math/rand"
    "os"
    "time"
)

func main() {
    L := len(os.Args)
    m, n, p, q, err := mapVars(L, os.Args)
    if err != 0 {
        fmt.Fprintf(os.Stderr, "error: Incorrect command line arguments.\n")
        os.Exit(1)
    }

    fmt.Println("The product array has dimensions.")
    fmt.Printf("\tC is %dx%d\n", m, q)

    fmt.Println("\nPopulating matrix A.")
    A, _ := createMat(m, n)
    fmt.Println("Matrix A.")
    printMat(m, A)

    fmt.Println("\nPopulating matrix B.")
    B, _ := createMat(p, q)
    fmt.Println("Matrix B.")
    printMat(p, B)

    fmt.Println("\nPerforming row-wise matrix-matrix multiplication AB.")
    startRow := time.Now()
    C := rowMultMat(m, n, q, A, B)
    dtRow := time.Since(startRow)
    fmt.Printf("Time elapsed: %v\n", dtRow)
    fmt.Println("Matrix C.")
    printMat(q, C)

}

func mapVars(l int, args []string) (m int, n int, p int, q int, err int) {
    if l == 2 {
        m, _ := strconv.Atoi(args[1])
        n, _ := strconv.Atoi(args[1])
        p, _ := strconv.Atoi(args[1])
        q, _ := strconv.Atoi(args[1])
        fmt.Printf("Creating two arrays, A, B, with square dimensions.\n")
        fmt.Printf("\tA is %dx%d\n\tB is %dx%d\n", m, n, p, q)
        return m, n, p, q, 0
    } else if (l == 5 || n != p) {
        m, _ := strconv.Atoi(args[1])
        n, _ := strconv.Atoi(args[2])
        p, _ := strconv.Atoi(args[3])
        q, _ := strconv.Atoi(args[4])
        fmt.Println("Creating two arrays, A, B, with dimensions.")
        fmt.Printf("\tA is %dx%d\n\tB is %dx%d\n", m, n, p, q)
        return m, n, p, q, 0
    } else {
        fmt.Println("Incorrect command line arguments.\n")
        return 0, 0, 0, 0, 1
    }   
}

func initMat(m int, n int) (M [][]float64, rows []float64) {
    M = make([][]float64, m)
    rows = make([]float64, n*m)
    for i := 0; i < m; i++ {
        M[i] = rows[i*n : (i+1)*n]
    }
    return M, rows
}

func createMat(m int, n int) (M [][]float64, rows []float64) {
    M = make([][]float64, m)
    rows = make([]float64, n*m)
    for i := 0; i < m; i++ {
        for j := 0; j < n; j++ {
            rows[i*n + j] = float64(rand.Int63()%10)
        }
        M[i] = rows[i*n : (i+1)*n]
    }
    return M, rows
}

func printMat(row int, M [][]float64) {
    for i := 0; i < row; i++ {
        fmt.Printf("%v\n", M[i])
    }
}

func rowMultMat(m int, n int, q int, A [][]float64, B [][]float64) (C [][]float64) {
    C, _ = initMat(m, q)
    var total float64 = 0.0
    for i := 0; i < m; i++ {
        for j := 0; j < q; j++ {
            for k := 0; k < n; k++ {
                total += A[i][k] * (B[k][j])
            }
            C[i][j] = total
            total = 0
        }
    }
    return C
}

目前,我正在初始化 rowmultmat 内的矩阵,因为我无法将 c 作为指向 2d 切片的指针传递。例如,run main.go 2 3 3 2 会将 2x3 与 3x2 相乘,得到 2x2。


解决方案


切片已经是一个参考值了。如果将切片传递给函数,该函数可以修改其内容 (*),并且一旦返回,调用者就可以看到这些修改。

或者,返回一个新切片也很有效 - 因为同样,切片只是引用,不会占用太多内存。

(*) 这里的内容是指切片指向的底层数组的内容。某些属性(例如切片长度)无法以这种方式更改;例如,如果您的函数需要使切片更长,则必须传入指向切片的指针。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于Golang的相关知识,也可关注golang学习网公众号。

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>