When the slice element is removed, the original slice is broken - go

package main
import (
"fmt"
)
func main() {
// test data
var a = [][]int{
[]int{1,2},
[]int{3,4},
[]int{5,6},
[]int{7,8},
}
for i := range a {
fmt.Println(a) // print out
_ = append(a[:i], a[i+1:]...) // remove element
}
}
expected result
[[1 2] [3 4] [5 6] [7 8]]
[[1 2] [3 4] [5 6] [7 8]]
[[1 2] [3 4] [5 6] [7 8]]
[[1 2] [3 4] [5 6] [7 8]]
actual result
[[1 2] [3 4] [5 6] [7 8]]
[[3 4] [5 6] [7 8] [7 8]]
[[3 4] [7 8] [7 8] [7 8]]
[[3 4] [7 8] [7 8] [7 8]]
https://play.golang.org/p/KahcX1MmDHO
why does this result? the original slice is broken. :(

When you re-slice you don't change the underlying array. So the first time through your loop (append(a[:0], a[1:]...)) you create a[:0] which is a slice of len 0 (cap 4) pointing to the element 0 and a[1:] is a slice of len 3 (cap 3) pointing to element 1.
As #icza pointed out using append() in this way just moved the underlying array elements around. For each loop iteration this happens:
0: elements 1-3 are moved to places 0-2
1: elements 2-3 are moved to places 1-2
2: element 3 is moved to place 2
3: nothing is moved since a[4:] has zero length
This gives the changed values that you see.
BTW Please post the simplest code which shows the problem. The nested slice is irrelevant.
func main() {
var a = []int{1,2,3,4}
for i := range a {
fmt.Println(a)
_ = append(a[:i], a[i+1:]...)
}
}

Related

Golang slice append exception

This is a leet code problem, and when I try to answer with the code blew:
package main
import "fmt"
func main() {
nums := []int{9, 0, 3, 5, 7}
fmt.Println(subsets(nums))
}
func subsets(nums []int) [][]int {
var result [][]int
result = append(result, []int{})
for _, v := range(nums) {
for _, rv := range(result) {
result = append(result, append(rv, v))
}
}
return result
}
Leetcode told me wrong answer:
Wrong Answer
Details
Input
[9,0,3,5,7]
Output
[[],[9],[0],[9,0],[3],[9,3],[0,3],[9,0,3],[5],[9,5],[0,5],[9,0,5],[3,5],[9,3,5],[0,3,5],[9,0,3,7],[7],[9,7],[0,7],[9,0,7],[3,7],[9,3,7],[0,3,7],[9,0,3,7],[5,7],[9,5,7],[0,5,7],[9,0,5,7],[3,5,7],[9,3,5,7],[0,3,5,7],[9,0,3,7,7]]
Expected
[[],[9],[0],[0,9],[3],[3,9],[0,3],[0,3,9],[5],[5,9],[0,5],[0,5,9],[3,5],[3,5,9],[0,3,5],[0,3,5,9],[7],[7,9],[0,7],[0,7,9],[3,7],[3,7,9],[0,3,7],[0,3,7,9],[5,7],[5,7,9],[0,5,7],[0,5,7,9],[3,5,7],[3,5,7,9],[0,3,5,7],[0,3,5,7,9]]
The output slice index 15, it should be [9,0,3,5] like the expected, but the result is [9,0,3,7].
So I try to run this code by go playgroud online,the answer is the same wrong, and then I run this code in goland with debug mode,I find when I make the slice append([9,0,3], 7), the output slice index 15 change at the same time.
My local go env: go version go1.17.6 windows/amd64
I'm just a beginner to golang, could anyone explain this situation?
Thank you very much.
ps: I try to use blew code to recover same issue, but I failed.
package main
import "fmt"
func main() {
a := [][]int{{}, {9}, {0}, {9, 0}, {3}, {9, 3}, {0, 3}, {9, 0, 3}, {5}, {9, 5}, {0, 5}, {9, 0, 5}, {3, 5}, {9, 3, 5}, {0, 3, 5}, {9, 0, 3, 5}}
i := 7
for _, v := range a {
// fmt.Println(a)
a = append(a, append(v, i))
// fmt.Println(a)
}
fmt.Println(a)
}
result:
[[] [9] [0] [9 0] [3] [9 3] [0 3] [9 0 3] [5] [9 5] [0 5] [9 0 5] [3 5] [9 3 5] [0 3 5] [9 0 3 5] [7] [9 7] [0 7] [9 0 7] [3 7] [9 3 7] [0 3 7] [9 0 3 7] [5 7] [9 5 7] [0 5 7] [9 0 5 7] [3 5 7] [9 3 5 7] [0 3 5 7] [9 0 3 5 7]]
You are reusing the same backing array in some of your slices, because that's what append does if there's capacity remaining. A simple fix is to replace append(rv, v) with append(append([]int{}, rv...), v), creating an entirely new slice. An alternative is to force the append to allocate a fresh backing array by capping the slice to its current length: append(rv[:len(rv):len(rv)], v).
Playground link with working code: https://go.dev/play/p/Gc-yF5KQOAO

How can you seed a first item with bufferWithCount in rx.js?

Say you do something like:
Rx.Observable.range(1, 5).bufferWithCount(2, 1).subscribe(console.log);
This returns:
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5]
I'd like for the result to look like (basically force the first value to emit):
[<userDefined>, 1]
[1, 2]
[3, 4]
etc...
How about:
Rx.Observable.range(1, 5)
// Note this value will get used for every subscription
// after it is defined.
.startWith(userDefined)
.bufferWithCount(2, 1)
.subscribe(console.log);

Update matrix in-place in Clojure

Suppose I have a Clojure matrix A as such (formatted for clarity)
[[1 4 3]
[1 7 3]
[1 8 3]]
Now suppose I want to update the first column in place, by e.g. multiplying it by a factor of two, so that the new matrix becomes
[[2 4 3]
[2 2 3]
[2 8 3]]
How would one do this in clojure? I have tried things like assoc and stuff like
(join-along 1 (* (slice A 1 0) 2) (select A [0 1 2] [2 3]))
Naturally that did not work. It would be great if there was something like assoc for matrices e.g.
(massoc A [rows] [columns] replacement-vector)
or something simple like numpy in Python:
A[:,0]*2 = [[2 4 3]
[2 2 3]
[2 8 3]]
Thanks
You should look into clojure.core/matrix and see if it supports operations like this.
Here is something that may be what you're looking for. It should be trivial to change this to assoc a new value rather than updating after applying a function.
(defn mupdate-in
"Update all `coll' rows at `column' with `f'"
[coll column f & args]
(reduce #(apply update-in %1 [%2 column] f args)
coll
(range (count coll))))
An example:
(def m [[1 4 3]
[1 7 3]
[1 8 3]])
(mupdate-in m 0 * 2)
;; [[2 4 3]
;; [2 7 3]
;; [2 8 3]]
(mupdate-in m 2 + 10)
;; [[1 4 13]
;; [1 7 13]
;; [1 8 13]]

Adding rows / columns to existing matrices in core.matrix (Clojure)

How does one add a row or a column to an existing matrix? I'm trying to add a bias-term, a column of ones, as the first row of a matrix. In Octave I can do this with:
M = [ones(size(M, 1), 1), M];
You can use the join function to append arrays along the major dimension.
And you can combine this with broadcast to get a matrix of ones in whatever size you like, e.g.:
e.g.
(join (broadcast 1 [1 3])
[[1 2 3]
[4 5 6]
[7 8 9]])
=> [[1 1 1]
[1 2 3]
[4 5 6]
[7 8 9]]

How do I write Ruby's each_cons in Clojure?

How can I rewrite this Ruby code in Clojure?
seq = [1, 2, 3, 4, 5].each_cons(2)
#=> lazy Enumerable of pairs
seq.to_a
=> [[1, 2], [2, 3], [3, 4], [4, 5]]
Clojure:
(??? 2 [1 2 3 4 5])
;=> lazy seq of [1 2] [2 3] [3 4] [4 5]
What you are asking for is called sliding window over a lazy sequence.This way you can achieve that
user=> (partition 2 1 [1 2 3 4 5])
((1 2) (2 3) (3 4) (4 5))

Resources