GoLang: How to delete an element from a 2D slice? - arrays

I've recently been messing around with Go and I wanted to see how it would be to delete an element from a two-dimensional slice.
For deleting an element from a one-dimensional slice, I can successfully use:
data = append(data[:i], data[i+1:]...)
However, with a two-dimensional slice, using:
data = append(data[i][:j], data[i][j+1:]...)
throws the error:
cannot use append(data[i][:j], data[i][j+1:]...) (type []string) as type [][]string in assignment
Would tackling this require a different approach?

A 2D slice in Go is nothing more than a slice of slices. So if you want to remove an element from this 2D slice, effectively you still only have to remove an element from a slice (which is an element of another slice).
There is nothing more involved. Only thing you have to look out is that when you remove an element from the row-slice, the result will only be the "new" value of the row (an element) of the "outer" slice, and not the 2D slice itself. So you have to assign the result to an element of the outer slice, to the row whose element you just removed:
// Remove element at the ith row and jth column:
s[i] = append(s[i][:j], s[i][j+1:]...)
Note that this is identical to the simple "removal from slice" if we substitute s[i] with a (not surprisingly, because s[i] denotes the "row-slice" whose jth element we're removing):
a = append(a[:j], a[j+1:]...)
See this complete example:
s := [][]int{
{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 10, 11},
}
fmt.Println(s)
// Delete element s[1][2] (which is 6)
i, j := 1, 2
s[i] = append(s[i][:j], s[i][j+1:]...)
fmt.Println(s)
Output (try it on the Go Playground):
[[0 1 2 3] [4 5 6 7] [8 9 10 11]]
[[0 1 2 3] [4 5 7] [8 9 10 11]]

Here is one of the possible approaches Go Playground.
b := [][]int{
[]int{1, 2, 3, 4},
[]int{5, 6, 7, 8},
[]int{9, 0, -1, -2},
[]int{-3, -4, -5, -6},
}
print2D(b)
i, j := 2, 2
tmp := append(b[i][:j], b[i][j+1:]...)
c := append(b[:i], tmp)
c = append(c, b[i+1:]...)
print2D(c)
Basically I am extracting the i-th row, remove the element from it append(b[i][:j], b[i][j+1:]...) and then put this row between the rows.
If someone would tell how to append many elements, it would look even nicer.

Related

How would you split a numpy array where the elements give the partition size?

For an numpy 1d array such as:
In [1]: A = np.array([2,5,1,3,9,0,7,4,1,2,0,11])
In [2]: A
Out[2]: array([2,5,1,3,9,0,7,4,1,2,0,11])
I need to split the array by using the values as a sub-array length.
For the example array:
The first index has a value of 2, so I need the first split to occur at index 0 + 2, so it would result in ([2,5,1]).
Skip to index 3 (since indices 0-2 were gobbled up in step 1).
The value at index 3 = 3, so the second split would occur at index 3 + 3, and result in ([3,9,0,7]).
Skip to index 7
The value at index 7 = 4, so the third and final split would occur at index 7 + 4, and result in ([4,1,2,0,11])
I'm using this simple array as an example, because I think it will help in my actual use case, which is reading data from binary files (either as bytes or unsigned shorts). I'm guessing that numpy will be the fastest way to do it, but I could also use struct/bytearray/lists or whatever would be best.
I hope this makes sense. I had a hard time trying to figure out how best to word the question.
Here is an approach using standard python lists and a while loop:
def custom_partition(arr):
partitions = []
i = 0
while i < len(arr):
pariton_size = arr[i]
next_i = i + pariton_size + 1
partitions.append(arr[i:next_i])
i = next_i
return partitions
a = [2, 5, 1, 3, 9, 0, 7, 4, 1, 2, 0, 11]
b = custom_partition(a)
print(b)
Output:
[[2, 5, 1], [3, 9, 0, 7], [4, 1, 2, 0, 11]]

Rearrange an array A so that A wins maximum number of comparisons with array B when comparison is done one-on-one

Let's say I have an array A = [3, 6, 7, 5, 3, 5, 6, 2, 9, 1] and B = [2, 7, 0, 9, 3, 6, 0, 6, 2, 6]
Rearrange elements of array A so that when we do comparison element-wise like 3 with 2 and 6 with 7 and so on, we have maximum wins (combinations where A[i] > B[i] are maximum (0<=i<len(A))).
I tried below approach:
def optimal_reorder(A,B,N):
tagged_A = [('d',i) for i in A]
tagged_B = [('a',i) for i in B]
merged = tagged_A + tagged_B
merged = sorted(merged,key=lambda x: x[1])
max_wins = 0
for i in range(len(merged)-1):
print (i)
if set((merged[i][0],merged[i+1][0])) == {'a','d'}:
if (merged[i][0] == 'a') and (merged[i+1][0] == 'd'):
if (merged[i][1] < merged[i+1][1]):
print (merged[i][1],merged[i+1][1])
max_wins += 1
return max_wins
as referenced from
here
but this approach doesn't seem to give correct answer for given A and B i,e if A = [3, 6, 7, 5, 3, 5, 6, 2, 9, 1] and B = [2, 7, 0, 9, 3, 6, 0, 6, 2, 6] then maximum wins is 7 but my algorithm is giving 5.
is there something I am missing here.
revised solution as suggested by #chqrlie
def optimal_reorder2(A,B):
arrA = A.copy()
C = [None] * len(B)
for i in range(len(B)):
k = i + 1
all_ele = []
while (k < len(arrA)):
if arrA[k] > B[i]:
all_ele.append(arrA[k])
k += 1
if all_ele:
e = min(all_ele)
else:
e = min(arrA)
C[i] = e
arrA.remove(e)
return C
How about this algorithm:
start with an empty array C.
for each index i in range(len(B)).
if at least one of the remaining elements of A is larger than B[i], choose e as the smallest of these elements, otherwise choose e as the smallest element of A.
set C[i] = e and remove e from A.
C should be a reordering of A that maximises the number of true comparisons C[i] > B[i].
There’s probably a much better algorithm than this, but you can think of this as a maximum bipartite matching problem. Think of the arrays as the two groups of nodes in the bipartite graph, then add an edge from A[i] to B[j] if A[i] > B[j]. Then any matching tells you how to pair elements of A with elements of B such that the A element “wins” against the B element, and a maximum matching tells you how to do this to maximize the number of wins.
I’m sure there’s a better way to do this, and I’m excited to see what other folks come up with. But this at least shows you can solve this in polynomial time.

selecting 2D sub-slice of a 2D-slice using ranges in go

I'm getting a surprising result when selecting a 2D sub-slice of a slice.
Consider the following 2D int array
a := [][]int{
{0, 1, 2, 3},
{1, 2, 3, 4},
{2, 3, 4, 5},
{3, 4, 5, 6},
}
To select the top left 3x3 2D slice using ranges I would use
b := a[0:2][0:2]
I would expect the result to be
[[0 1 2] [1 2 3] [2 3 4]]
however the second index range doesn't seem to have any effect, and returns the following instead:
[[0 1 2 3] [1 2 3 4] [2 3 4 5]]
What am I missing? Can you simply not select a sub-slice like this where the dimension > 1 ?
You can't do what you want in a single step. Slices and arrays are not 2-dimensional, they are just composed to form a multi-dimensional object. See How is two dimensional array's memory representation
So with a slice expression, you just get a slice that will hold a subset of the "full" rows, and its type will be the same: [][]int. If you slice it again, you just slicing the slice of rows again.
Also note that the higher index in a slice expression is exclusive, so a[0:2] will only have 2 rows, so you should use a[0:3] or simply a[:3] instead.
To get what you want, you have to slice the rows individually like this:
b := a[0:3]
for i := range b {
b[i] = b[i][0:3]
}
fmt.Println(b)
This will output (try it on the Go Playground):
[[0 1 2] [1 2 3] [2 3 4]]
Or shorter:
b := a[:3]
for i, bi := range b {
b[i] = bi[:3]
}

Get the element's order map of an array

For example:
if input is {2, 8, 5, 6, 10},
the output will be {1, 4, 2, 3, 5} .
Since 2 in the minimum in the source array, it's order is 1. 10 is maximum in the array, so it's order is the length of input array.
It's easy to sort the input array first and then find the index of each element. But I want to know if there is a more optimized way.
It doesn't matter whether the order is zero-based or one-based.
Replace each element by a pair: (element, index). {2,8,5,6,10} becomes {(2,1),(8,2),(5,3),(6,4),(10,5)}. Let this array be A.
Sort A. You now have {(2,1),(5,3),(6,4),(8,2),(10,5)}
For each i from 1 to length(A) do B[A[i].second_element] <- i. In your case:
B[1] <- 1
B[3] <- 2
B[4] <- 3
B[2] <- 4
B[5] <- 5
Now B={1,4,2,3,5}. PROFIT!!!

How Can I Creat Method do This Job?

I want create method that return an array which contains exactly the same numbers as the given array, but rearranged so that every 3 is immediately followed by a 4.
Do not move the 3's, but every other number may move. The array contains the same number of 3's and 4's, every 3 has a number after it that is not a 3 or 4, and a 3 appears in the array before any 4.
Example:
problem({1, 3, 1, 4, 4, 3, 1}) → {1, 3, 4, 1, 1, 3, 4}
problem({3, 2, 2, 4}) → {3, 4, 2, 2}
thanks .
Set i = 0, j = 0. Then you repeat the following:
Find the first 3 at an index ≥ i which is not followed by a 4. If none are found, you succeeded. If the 3 is the last number in the array or followed by a 3, you failed. Now find the first 4 at an index ≥ j which is not preceded by a 3. If none are found, you fail. Otherwise set i = location of the 3, j = location of the 4, exchange the objects at positions i+1 and j, set i = i + 2 and j = j + 1, and repeat.
I don't like writing code that depends on promises about the data that I don't verify myself, so this will work whatever is in the array.

Resources