如何向2维切片追加元素

3
我有一些数据是逐行创建的,有6列,我不知道预先有多少行。
目前我正在创建一个2D大小为200x6的全零切片,然后我逐行逐渐地用我的数据替换这些零。 数据来自另一个名为df的数据框。
它可以工作,但我不喜欢最后几行切片都是零。 我看到两个解决方案: - 当完成时,删除所有只有零的最后几行 - 创建一个空切片,并逐步将我的数据附加到其中
我尝试了各种方法,但无法编写任何这两个解决方案的代码。
目前,我的代码如下:
var orders [200][6]float64  // create my 2d slice with zeros
order_line := 0

for i := start_line; i <= end_line; i++ {
    if sell_signal == "1" {
        //record line number and sold price in orders slice
        orders[order_line][1] =  float64(i+1)
        orders[order_line][2],err = strconv.ParseFloat(df[i][11], 64)
        order_line = order_line + 1
     }
}

我看了一下Append命令,但是我尝试了各种组合来让它在二维切片上工作,但没有找到可行的方法。

编辑:根据下面的评论,我理解我实际上是在创建一个数组,而不是切片,因此没有办法向数组中添加数据。


1
通过使用“[数字]”符号来指定大小,您不是创建一个切片,而是创建一个数组。 - RayfenWindspear
1
一个问题,为什么你首先要使用数组/切片来做这件事?这似乎更适合使用一个包含结构体的单维切片,每个结构体都包含并提供字段名称,而不是索引。这样做对可读性更好,但再次强调,它取决于你想要/需要使用数组/切片的原因。 - RayfenWindspear
哦,糟糕,这就解释了为什么我一直那么困难。但是,我的问题仍然存在,有没有一种方法可以将数据附加到二维数组中?还是在完成后删除我的零更简单? - Hugues
1
你不能向数组中添加或删除元素,因为数组的大小是固定的。这里似乎更适合使用切片。 - Charlie Tumahai
Go语言中没有二维切片(或者说数组,就像你实际代码中的那样)。只有切片的切片或者数组的数组。 - Jonathan Hall
3个回答

6
在Golang中,推荐使用切片来代替数组。
不需要事先创建很多行,每次在循环遍历数据以添加新行到父切片时,只需创建一个切片即可。这样将帮助您仅拥有所需数量的行,并且您无需担心长度问题,因为您是将切片追加到父切片的索引位置。
package main

import (
    "fmt"
    "math/rand"
)

func main() {
    orders := make([][]float64, 0) // create my 2d slice with zeros
    for i := 0; i <= 6; i++ {
        value := rand.Float64()
        temp := make([]float64, 0)
        temp = append(temp, value)
        orders = append(orders, [][]float64{temp}...)
    }
    fmt.Println(orders)
}

请在Playground上查看工作代码。
如果您注意到我在循环中创建了一个新的temp切片,其中包含float64值,然后将该值附加到我传递给父切片的temp切片中。
因此,每次我将temp切片附加到父切片时,都会创建一个新行。
请注意:
引用:
数组有其存在的意义,但它们有点不灵活,所以您不会在Go代码中经常看到它们。切片则无处不在。它们建立在数组的基础上,提供了巨大的功能和便利性。
编辑后:
要在前三列上操作,然后操纵下三列的值,这些值将添加到temp切片中并附加到主切片中。使用以下代码逻辑:
package main

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

func main() {
    orders := make([][]float64, 0) // create my 2d slice with zeros
    for i := 0; i <= 6; i++ {
        value := rand.Float64()
        // logic to create first 3 columns
        temp := make([]float64, 0)
        temp = append(temp, value)

        temp2 := make([]float64, 3)

        // logic to create next 3 columns on basis of previous 3 columns
        for j, value := range temp {
            addcounter, _ := strconv.ParseFloat("1", 64)
            temp2[j] = value + addcounter
        }

        temp = append(temp, temp2...)
        orders = append(orders, [][]float64{temp}...)
    }
    fmt.Println(orders)
}

工作示例


我喜欢你添加的注释。如果你专门使用数组,那么你必须编写自己的代码来利用它。在任何库中,几乎没有任何东西能够原生地利用导出 API 中的数组。 - RayfenWindspear
@RayfenWindspear,很抱歉我没有理解你的观点,我写的笔记是针对golang的。这就是为什么在为golang创建的库中,你总是看到切片代替数组的原因。此外,从开发者的角度来看,使用切片更加舒适,因为你不需要担心长度,它会根据需要使用内置函数append进行增长。 - Himanshu
我的评论的重点是Go在各个地方都使用切片,因此,如果您出于某种原因使用数组编写代码,则必须继续编写自己的代码来使用它们。其他地方都不会使用它们,因此您不能简单地将它们传递到另一个库中。即不要使用数组。 - RayfenWindspear
@RayfenWindspear 哦,我明白了。在这种情况下,你是完全正确的。切片被用于代替数组的所有地方。 - Himanshu
@Himanshu,我唯一不确定的是:我有6列数据,我计算前3列的数据,然后再计算依赖于前3列数据的更多数据以得到最后3列数据。我能先附加一行的前3列,然后稍后再写入同一行的最后3列吗?还是只能附加到新行? - Hugues
1
@Hugues 是的,你可以创建另一个临时切片,并将其附加到第一个临时切片,然后将整个切片附加到父切片。 - Himanshu

3
鉴于外层容器具有未知数量的元素,而内层容器恰好有六个元素,请使用数组切片。
var orders [][6]float64
for i := start_line; i <= end_line; i++ {
    if sell_signal == "1" {
        n, err = strconv.ParseFloat(df[i][11], 64)
        if err != nil {
            // handle error
        }
        orders = append(orders, [6]float64{1: float64(i + 1), 2: n})
    }
}

这段代码使用了一个组合字面量[6]float64值,而不像问题中一样逐个赋值元素。
您可以稍后返回并访问[6]float64的元素。例如:
 orders[i][3] = orders[i][1] + orders[i][2]

使用这个方法,我可以用两步追加一行吗?也就是说我可以先追加行的前三列,然后做其他事情,再回来完成同一行的后三列吗? - Hugues
基于其他问题的评论,我假设所有行都包含6个元素。这正确吗?如果是这样,就没有必要在此答案中添加更多值。 - Charlie Tumahai
1
这个答案中的每一行都是一个六元素数组。在复合字面量中未明确设置的元素将被初始化为零。您可以随时使用索引表达式访问数组的元素,例如 orders[i][3] - Charlie Tumahai

1
为了更好的可读性和更容易的切片处理,只需创建一个结构体类型并用它们填充一个切片。这样可以适当地命名每个字段,而不是使用魔术索引数字,并且更容易填写行以及稍后利用它们。除非有某些特定的原因需要使用数组/切片来表示列,否则这是更符合Go语言惯例的做法。以下示例将用任意数量的结果填充一个切片,但不超过所需数量。
完整示例请参见:https://play.golang.org/p/mLtabqO8MNj
type Row struct {
    Thing   float64
    Data    float64
    More    float64
    Stuff   float64
    Another float64
    Number  float64
}

var rows []*Row

numResults := 15
for i := 0; i <= numResults; i++ {
    row := &Row{}
    row.Thing = 2.5
    // ... fill values
    rows = append(rows, row)
}

使用这种方法,我可以分2次添加一行吗?意思是我先添加一行的前3列,然后做其他事情,再回来完成后3列吗? - Hugues
1
@Hugues 是的。如果“做其他事情”后row结构体仍在作用域内,您可以直接设置值。否则,您只需要知道您正在处理的行的索引,并可以通过这种方式访问它,例如rows[i].More = 1.1。您可以在任何时候将row附加到切片中,并且仍然可以通过索引稍后进行修改,如果您愿意的话。 - RayfenWindspear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接