Is it possible to slice an inner matrix with brackets? - go

I am modifying the perimeter values on a matrix, then trying to recurse into the inner values. I expected I'd be able to access the inner values with something like matrix[1:3][1:3]. This is not the case, and I'm a bit lost as to the underlying logic of how Go handles sequential brackets.
package main
import (
"fmt"
)
var m = [][]int{
[]int{0, 1, 2, 3},
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
[]int{12, 13, 14, 15},
}
I am trying to access the values 5, 6, 9, 10 in the above matrix -- the "inner" matrix.
func main() {
inner := m[1:3][1:3]
fmt.Printf("%#v\n", inner)
// Expected Output: [][]int{
// []int{5, 6},
// []int{9, 10}
// }
// Actual Ouput: [][]int{
// []int{8, 9, 10, 11},
// []int{12, 13, 14, 15}
// }
inner = m[1:3]
fmt.Printf("%#v\n", inner)
// Output:
// [][]int{
// []int{4, 5, 6, 7},
// []int{8, 9, 10, 11}
// }
inner = innerMatrix(m)
fmt.Printf("%#v\n", inner)
// [][]int{
// []int{5, 6},
// []int{9, 10}
}
func innerMatrix(m [][]int) (inner [][]int) {
innerRows := m[1:3]
for _, row := range innerRows {
inner = append(inner, row[1:3])
}
return
}
The function innerMatrix is able to produce the output I expected. I'm lost as to why (1) m[1:3][1:3] doesn't have the same effect, (2) it seems to translate to m[2:4]. What's going on?
Playground

When you create a sub-slice in Go, you're allowed to grow that sub-slice back to the capacity of the original slice again, e.g.:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
b := a[1:3]
fmt.Printf("a[1:3]: %v\n", b)
c := b[1:3]
fmt.Printf("b[1:3]: %v\n", c)
}
which outputs:
a[1:3]: [2 3]
b[1:3]: [3 4]
Note that b only has two elements, but we're allowed to create a slice of the second and third elements because the capacity of the slice it's a sub-slice of is sufficiently large, and all the slices share the same underlying array. See the last example in section "Slice internals" on this page
So what's happening in your case is that m[1:3] is equivalent to:
var m1 = [][]int{
[]int{4, 5, 6, 7}, // second element of m
[]int{8, 9, 10, 11}, // third element of m
}
and m[1:3][1:3] is therefore equivalent to m1[1:3], which is equivalent to:
var m2 = [][]int{
[]int{8, 9, 10, 11}, // second element of m1
[]int{12, 13, 14, 15}, // "third" element of m1
}
with the "third" element appearing only because the capacity of m is large enough to contain it, and does in fact contain it. If m only had three elements, this would cause a panic.
In other words, m[1:3][1:3] is here exactly equivalent to m[2:4], because m[1:3][1:3] gives you the second and third elements of m[1:3]. Maybe easier to understand with a diagram:
m : []int{1, 2, 3, 4}
m[1:3] : []int{ 2, 3 }
m[1:3][1:3] : []int{ 3, 4}
m[2:4] : []int{ 3, 4}
As an oversimplification, you can imagine that the square brackets give the requested elements of whatever is immediately to the left of them, so a somewhat extreme example:
package main
import "fmt"
func main() {
a := []int{1, 2, 3, 4, 5}
b := a[1:5]
fmt.Printf("b: %v, a[1:5] : %v\n",
b, a[1:5])
c := b[1:4]
fmt.Printf("c: %v , a[1:5][1:4] : %v\n",
c, a[1:5][1:4])
d := c[1:3]
fmt.Printf("d: %v , a[1:5][1:4][1:3] : %v\n",
d, a[1:5][1:4][1:3])
e := d[1:2]
fmt.Printf("e: %v , a[1:5][1:4][1:3][1:2]: %v\n",
e, a[1:5][1:4][1:3][1:2])
}
which outputs:
b: [2 3 4 5], a[1:5] : [2 3 4 5]
c: [3 4 5] , a[1:5][1:4] : [3 4 5]
d: [4 5] , a[1:5][1:4][1:3] : [4 5]
e: [5] , a[1:5][1:4][1:3][1:2]: [5]

Here is your data:
var m = [][]int{
[]int{0, 1, 2, 3},
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
[]int{12, 13, 14, 15},
}
First you ask what is inner := m[1:3][1:3]?
Well, taking one at a time, m[1:3] is the subslice you get when grabbing elements 1 to 3 not including 3. So that is elements 1 and 2. Element 0 is []int{0, 1, 2, 3}, element 1 is []int{4, 5, 6, 7}, and element 2 is []int{8, 9, 10, 11},
So m[1:3] is
[][]int{
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
}
Now, to get m[1:3][1:3] we repeat the same thing on this result.
However, this time, there are only two elements. We again want elements 1 and 2. We skip element 0 which is []int{4, 5, 6, 7}. Element 1 is []int{8, 9, 10, 11}. There is no element 2. However, the result of m[1:3] was a subslice and the underlying slice had an additional element.
So by extending this subslice we can get that element back again, and that is the hiddent element 2 which is []int{12, 13, 14, 15}.
So m[1:3][1:3] is
[][]int{
[]int{8, 9, 10, 11},
[[]int{12, 13, 14, 15},
}
Finally, you wonder why func innerMatrix works differently? It starts by producing m[1:3] which is
[][]int{
[]int{4, 5, 6, 7},
[]int{8, 9, 10, 11},
}
Then the code IS NOT taking another subslice in the same way that m[1:3][1:3] is two consecutive subslices. Instead, you take each element in the slice and grab the subslice from each element. The first time through you grab subslices [1:3] from []int{4, 5, 6, 7}. The result of that is
[]int{5, 6}
The second time through you do the same on the second element []int{8, 9, 10, 11} which is
[]int{9, 10}
Finally, each time through you append the result to the result slice, so you append []int{5, 6} to [], to give [][]{int{5, 6}}, and then you append []int{9, 10} to give
[][]{int{5, 6}, []int{9, 10} }

Related

Replace multiple indexes with one value

I have an array that has the value
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I want to replace indexes 1 to 3, [2, 3, 4], with the single value of 123.
Is there a way to do this in golang?
Rather than use an array you should be working with slices.
a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
b := append(append(a[:1:1], 123), a[4:]...)
Or if you don't need to keep the original elements then copy in place.
a := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
a[1] = 123
copy(a[2:8], a[4:10])
a = a[:8]

Golang - How to remove a row from a matrix?

So I have this 2D slice, for example:
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
fmt.Println(s)
//Outputs: [[0 1 2 3] [4 5 6 7] [8 9 10 11]]
How can I remove a full row from this 2D slice, so that the result would look like this if I decide to remove the middle row:
[[0 1 2 3] [8 9 10 11]]
The formula to delete row at index i is:
s = append(s[:i], s[i+1:])
Here's a working example:
package main
import (
"fmt"
)
func main() {
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7}, // This will be removed.
{8, 9, 10, 11},
}
// Delete row at index 1 without modifying original slice by
// appending to a new slice.
s2 := append([][]int{}, append(s[:1], s[2:]...)...)
fmt.Println(s2)
// Delete row at index 1. Original slice is modified.
s = append(s[:1], s[2:]...)
fmt.Println(s)
}
Try it in the Go playground.
I recommend you to read Go Slice Tricks. Some of the tricks can be applied to multidimensional slices as well.
You can try the following:
i := 1
s = append(s[:i],s[i+1:]...)
You can try the working code in the Golang playground
Another alternative way is to use the following:
i := 1
s = s[:i+copy(s[i:], s[i+1:])]
Golang Playground

How to separate numbers from a slice?

Let's say I have a list with 10 numbers:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I would like my program to slice every 3 numbers, for example:
[1,2,3]
[4,5,6]
[7,8,9]
How can I do it?
Grateful
For example, with n = 3,
package main
import "fmt"
func main() {
list := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
for a, n := list, 3; len(a) >= n; a = a[n:] {
slice := a[:n]
fmt.Println(slice)
}
}
Output:
[1 2 3]
[4 5 6]
[7 8 9]
you could make a something like this (sorry for pseudo code)
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
while (array){
list = ""
for($i=1;$i -le 3;$i++){
list.add = array[$i]
remove from array the array[$i]
}
your list now here (list)
}
you could ask the first 3 values and after that you remove it

What is the fastest way to join multiple subsets that have similar elements?

I have a list with 500+ thousand subsets each having from 1 to 500 values (integers). So i have something like:
{1, 2, 3 }
{2, 3}
{4, 5}
{3, 6, 7}
{7, 9}
{8, 4}
{10, 11}
After running the code I would like to get:
{1, 2, 3, 6, 7, 9}
{4, 5, 8}
{10, 11}
I wrote simple code [here] that compares each subset to each subset, if they intersect they are joined together, else not.
It is ok on small scale, but with big amount of data it takes forever.
Please, could you advise any improvements?
P.S. I am not strong in maths or logics, big O notation would be greek for me. I am sorry.
You're trying to find the connected components in a graph, with each of your input sets representing a set of nodes that's fully connected. Here's a simple implementation:
sets = [{1, 2, 3 },{2, 3},{4, 5},{3, 6, 7},{7, 9},{8, 4},{10, 11}]
allelts = set.union(*sets)
components = {X: {X} for X in allelts}
component = {X: X for X in allelts}
for S in sets:
comp = sorted({component[X] for X in S})
mergeto = comp[0]
for mergefrom in comp[1:]:
components[mergeto] |= components[mergefrom]
for X in components[mergefrom]:
component[X] = mergeto
del components[mergefrom]
That results in components having a list of components (keyed by their minimum element), and component storing the components for each element:
>>> print(components)
{1: {1, 2, 3, 6, 7, 9}, 4: {8, 4, 5}, 10: {10, 11}}
>>> print(component)
{1: 1, 2: 1, 3: 1, 4: 4, 5: 4, 6: 1, 7: 1, 8: 4, 9: 1, 10: 10, 11: 10}
>>>

How can I implement such a map-like operation in mathematica

I have a list and an arbitrary function taking 4 parameters, let's say {1, 11, 3, 13, 9, 0, 12, 7} and f[{x,y,z,w}]={x+y, z+w}, what I want to do is to form a new list such that 4 consecutive elements in the original list are evaluated to get a new value as the new list's component, and the evaluation has to be done in every 2 positions in the original list, in this case, the resulting list is:
{{12, 16}, {16, 9}, {9, 19}}
Note here 4 and 2 can change. How to do this conveniently in Mathematica? I imagine this as something like Map, but not sure how to relate.
There's an alternative to Map[f, Partition[...]]: Developer`PartitionMap. Which works exactly like Map[f, Partition[list, n, ...]]. So, your code would be
Needs["Developer`"]
f[{x_, y_, z_, w_}] = {x + y, z + w};
list = {1, 11, 3, 13, 9, 0, 12, 7};
PartitionMap[f,list, 4, 2]
giving the same result as Mark's answer.
f[{x_, y_, z_, w_}] = {x + y, z + w};
list = {1, 11, 3, 13, 9, 0, 12, 7};
f /# Partition[list, 4, 2]

Resources