How to remove element of struct array in loop in golang - arrays

Problem
I have array of structs:
type Config struct {
Applications []Application
}
Note: Config - is a struct for json.Decode.
config = new(Config)
_ = decoder.Decode(&config)
In loop I have some condition and element deletion by key.
for i, application := range config.Applications {
if i == 1 {
config.Applications = _removeApplication(i, config.Applications)
}
}
func _removeApplication(i int, list []Application) []Application {
if i < len(list)-1 {
list = append(list[:i], list[i+1:]...)
} else {
log.Print(list[i].Name)
list = list[:i]
}
return list
}
But always I have "out of range" error. What is the best way to delete element by key from array of structs?

Quoting from the Slice Tricks page deleting the element at index i:
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
Note that if you plan to delete elements from the slice you're currently looping over, that may cause problems. And it does if the element you remove is the current one (or a previous element already looped over) because after the deletion all subsequent elements are shifted, but the range loop does not know about this and will still increment the index and you skip one element.
You can avoid this by using a downward loop:
for i := len(config.Applications) - 1; i >= 0; i-- {
application := config.Applications[i]
// Condition to decide if current element has to be deleted:
if haveToDelete {
config.Applications = append(config.Applications[:i],
config.Applications[i+1:]...)
}
}

You are getting this error because you are doing a loop over a slice with an inital range of X length that became X-n because you remove some elements during loop.
If you want to delete an item at a specific index from a slice, you can do it this way:
sliceA = append(sliceA[:indexOfElementToRemove], sliceA[indexOfElementToRemove+1:]...)

This question is a bit older but I haven't found another answer on StackOverflow which mentions the following trick from the Slice Tricks to filter a list:
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
So in this case a function which deletes certain elements could look like this:
func removeApplications(apps []Applications) []Applications {
filteredApps := apps[:0]
for _, app := apps {
if !removeApp {
filteredApps = append(filteredApps, app)
}
}
return filteredApps
}

I think the simple way is
var (
slice = []int{1,2,3,4,5}
pos int
)
for _, i := range slice {
if i == 3 {
slice = append(slice[:pos], slice[pos+1:]...)
if pos > 0 {
pos = pos - 1
}
continue
}
pos++
}
here is...
https://play.golang.org/p/pK3B5Mii9k

To remove a particular slice from a struct we need to run a for-loop to find that particular slice and delete it
for example:
type variable struct {
Id int `json:"id"`
Message string `json:"message"`
}
var mssg = []variable{
{Id: 1, Message: "success"},
{Id: 2, Message: "failed"}
}
for i, a := range mssg {
if a.Message == "success" {
mssg = append(mssg[:i], mssg[i+1:]...)
fmt.Println(mssg)
}

Related

Remove Adjacent Duplicates in string slice

I have a problem statement to write an in-place function to eliminate the adjacent duplicates in a string slice.
I came up with the following code
func main() {
tempData := []string{"abc", "abc", "abc", "def", "def", "ghi"}
removeAdjacentDuplicates(tempData)
fmt.Println(tempData)
}
func removeAdjacentDuplicates(data []string) {
for j := 1; j < len(data); {
if data[j-1] == data[j] {
data = append(data[:j], data[j+1:]...)
} else {
j++
}
}
fmt.Println(data)
}
The output is following
[abc def ghi]
[abc def ghi ghi ghi ghi]
My doubt is, if in the function, slice is modified, then in the calling function, why isn't the slice giving correct results?
Also, any article to understand the slices (and the underlying array) much better would be very helpful.
The func removeAdjacentDuplicate takes the slice "as if" it is a reference to tempData
The capacity and length of tempData in the main() stays the same for the lifetime
of the program
In the removeAdjacentDuplicate func each time a dupe is found the final value of "ghi" is moved from the end to the end - 1. So in the memory at the end of the
slice there are repeated "ghi"
When the control returns to the main, the program prints out the now modified
slice tempData. Because it was passed in a similar way to a reference to the
function it is this memory that was modified. The function call did not make a copy of the memory
You can see this behaviour by looking at the cap() and len() as the program runs
package main
import (
"fmt"
)
func main() {
tempData := []string{"abc", "abc", "abc", "def", "def", "ghi"}
removeAdjacentDuplicates(tempData)
fmt.Println(tempData,cap(tempData),len(tempData))
}
func removeAdjacentDuplicates(data []string) {
for j := 1; j < len(data); {
if data[j-1] == data[j] {
data = append(data[:j], data[j+1:]...)
fmt.Println(data,cap(data),len(data))
} else {
j++
}
}
fmt.Println(data, cap(data),len(data))
}
In your code, removeAdjacentDuplicates wants to mutate the slcie passed in argument. This is not really possible.
This function should return the new slice, just like append does.
func removeAdjacentDuplicates(data []string) []string{
for j := 1; j < len(data); {
if data[j-1] == data[j] {
data = append(data[:j], data[j+1:]...)
} else {
j++
}
}
return data
}
If you really want to mutate the argument, it is possible but you need to pass a pointer to a slice *[]string
Go 1.18 and above
You can use slices.Compact exactly for this.
Compact replaces consecutive runs of equal elements with a single copy. This is like the uniq command found on Unix. Compact modifies the contents of the slice s; it does not create a new slice.
func main() {
data := []string{"abc", "abc", "abc", "def", "def", "ghi"}
data = slices.Compact(data)
fmt.Println(data) // [abc def ghi]
}
The package is golang.org/x/exp/slices, which is still experimental. If you don't want to import an exp package, you can copy the source:
func Compact[S ~[]E, E comparable](s S) S {
if len(s) == 0 {
return s
}
i := 1
last := s[0]
for _, v := range s[1:] {
if v != last {
s[i] = v
i++
last = v
}
}
return s[:i]
}
If the slice's elements aren't comparable, use slices.CompactFunc which works the same but takes also a comparator function.
Try this function:
func deleteAdjacentDuplicate(slice []string) []string {
for i := 1; i < len(slice); i++ {
if slice[i-1] == slice[i] {
copy(slice[i:], slice[i+1:]) //copy [4] where there is [3, 4] => [4, 4]
slice = slice[:len(slice)-1] //removes last element
i-- //avoid advancing counter
}
}
return slice
}

Print matrix as string in golang

I have a matrix of integers, represented by a multivariate array. I'm trying to concatenate the numbers into a string representation, rows-by-columns. My naive approach is to walk over all entries in the matrix and append them to a nullstring.
However, I'm getting an error that my append function is saying:
./main.go:xx:yy: first argument to append must be slice; have string
My code is:
type MatString string
type IntMat [3][3]Int // external constraints require fixed size, symmetric.
func Matrix2String(t IntMat) MatString {
// s var string
s := ""
for i := range t {
for j := range t[i] {
s = append(s[:], fmt.Sprintf("%s", j))
// fmt.Sprintf(s)
}
}
return MatString(s)
}
What am I misunderstanding about arrays, slices, and joins, and how can I iteratively build up this string correctly?
Collect the elements in a slice of strings. Join the slice to produce the result.
func Matrix2String(t IntMat) MatString {
var s []string
for i := range t {
for _, n := range t[i] {
s = append(s, fmt.Sprintf("%d", n))
}
}
return MatString(strings.Join(s, ""))
}
Another approach is to build the string in a []byte and convert at the end:
func Matrix2String(t IntMat) MatString {
var s []byte
for i := range t {
for _, n := range t[i] {
s = strconv.AppendInt(s, int64(n), 10)
}
}
return MatString(s)
}
I didn't include any delimiters because the question didn't include them.
You can simply concatenate converted integers to strings, to the response
func Matrix2String(t IntMat) MatString {
s := ""
for i := range t {
for _, n := range t[i] {
s += fmt.Sprintf("%d", n)
}
}
return MatString(s)
}
Playground

Algorithm to list all tuples from an array of String

I'm trying to solve the following problem, given an array of String, of size n, list all n-tuples from this array, that is:
let A: [String] = ["a","b","c",...]
determine all the tuples
["abc..","bac..",...], of which there are exactly n!.
I've written a solution in Swift, but I'm not quite happy with the result, as it uses closures, making it difficult to iterate over the tuples.
Here's the code, just in case:
public func tuple(seq:[String], value:String, block:(String) -> ()) {
if seq.count > 0 {
for i in 0..<seq.count {
var uu = seq;
let kk:String = uu[i];
uu.remove(at: i)
self.tuple(seq:uu,value: value + kk, block: block)
}
} else {
block(value)
}
}
Anyone with a valid solution without closure?
Using the code from Sequence-based enumeration of permutations in lexicographic order on Code Review (updated for
Swift 4, and with the suggestions from Hamish's answer implemented):
extension Array where Element: Comparable {
/// Replaces the array by the next permutation of its elements in lexicographic
/// order.
///
/// It uses the "Algorithm L (Lexicographic permutation generation)" from
/// Donald E. Knuth, "GENERATING ALL PERMUTATIONS"
/// http://www-cs-faculty.stanford.edu/~uno/fasc2b.ps.gz
///
/// - Returns: `true` if there was a next permutation, and `false` otherwise
/// (i.e. if the array elements were in descending order).
mutating func permute() -> Bool {
// Nothing to do for empty or single-element arrays:
if count <= 1 {
return false
}
// L2: Find last j such that self[j] < self[j+1]. Terminate if no such j
// exists.
var j = count - 2
while j >= 0 && self[j] >= self[j+1] {
j -= 1
}
if j == -1 {
return false
}
// L3: Find last l such that self[j] < self[l], then exchange elements j and l:
var l = count - 1
while self[j] >= self[l] {
l -= 1
}
self.swapAt(j, l)
// L4: Reverse elements j+1 ... count-1:
var lo = j + 1
var hi = count - 1
while lo < hi {
self.swapAt(lo, hi)
lo += 1
hi -= 1
}
return true
}
}
struct PermutationSequence<Element : Comparable> : Sequence, IteratorProtocol {
private var current: [Element]
private var firstIteration = true
init(startingFrom elements: [Element]) {
self.current = elements
}
init<S : Sequence>(_ elements: S) where S.Iterator.Element == Element {
self.current = elements.sorted()
}
mutating func next() -> [Element]? {
var continueIterating = true
// if it's the first iteration, we avoid doing the permute() and reset the flag.
if firstIteration {
firstIteration = false
} else {
continueIterating = current.permute()
}
// if the array changed (and it isn't the first iteration), then return it,
// else we're at the end of the sequence.
return continueIterating ? current : nil
}
}
one can very efficiently iterate over all permutations of an array:
let a = ["a", "b", "c"]
let permSeq = PermutationSequence(startingFrom: a)
for tuple in permSeq {
print(tuple.joined())
}
Each call to the iterator creates the next permutation, and only a
fixed amount of additional storage is needed (one array for the
current permutation, and a boolean variable).
I am not sure why you need the closure to just generate the list. Here is what have used in the past. There is probably a 1 liner using flatmap.
func tuple(_ input:[String])->[String]{
print()
if input.count == 1 {return input}
var output = Array<String>()
for a in 0...input.count-1 {
var temp = input
temp.remove(at: a)
output += tuple(temp).map{input[a]+$0}
}
return output
}
print(tuple(a))

Inserting integer into array in swift

I'm not really on point with Swift yet and there is a problem that is starting to be a tad annoying.
I just want to add integer in a double dimensional array but it is always returning the same error code : "fatal error : Array index out of range"
var arrayVolley = [[Int]]()
init(){
self.arrayVolley = [[]]
}
Here is where I try to insert :
func addPoints(score : Int, x : Int, y : Int){
if (score > 11 || score < 0){ //11 will be translated as 10x
println("Error on score value")
}
else {
if (x>6 || y>6){
println("Out of array")
}
else{
arrayVolley[x][y]=score
}
}
}
And this is my main :
var i=0
var j=0
for i in 0...6 {
for j in 0...6{
println("Entrez le score")
var scoreinput=input()
var score = scoreinput.toInt()
distance.addPoints(score!, x: i, y: j)
}
}
Thanks a lot for your help in advance
Try to use append to add the integer to the array it is automatically the next idex. It think if the index was never used it gives an error e.g.
var test = [Int]()
test.append(2) // array is empty so 0 is added as index
test.append(4)
test.append(5) // 2 is added as max index array is not [2,4,5]
test[0] = 3 // works because the index 0 exist cause the where more then 1 element in array -> [3,4,5]
test[4] = 5 // does not work cause index for never added with append
or you intialize the array in the correct size, but it's need a size:
var test = [Int](count: 5, repeatedValue: 0) // [0,0,0,0,0]
test[0] = 3 //[3,0,0,0,0]
test[4] = 5 [3,0,0,0,5]
It hope this helps you if not please feel free to comment.

Unity3D the best way to loop through multiple dimension arrays

I am developing a game that has a winning combination array:
var allwinning = [
['000','010','020'],
['000','100','200'],
['000','001','002'],
['000','101','202'],
['000','011','022'],
['000','110','220']];
The player will need to pick more than 3 numbers randomly. If all numbers are within any of the combinations in allwinning, the player wins.
For example, if the player picks '111','110','000','220', the player will win because allwinning[5] has the combination['000','110','220'].
My question is, what is the best way to do this winning loop? I cannot figure out the optimum way to do this.
Currently, I have a playerpick array to keep what player had picked and possiblewin array:
var playerpick = new Array(['111','110','000','220']);
var playerpicksingle = playerpick[0];
var possiblewin = new Array([]);
Then I go through a loop to capture out the possible win combination first:
for(var i=0 ; i < allwinning.length - 1 ; i++)
{
for(var j=0 ; j <3 ; j++)
{
if(allwinning[i][j]==playerpicksingle)
{
possiblewin.Push(allwinning[i]);
}
}
}
Then I am stuck at this point. I really don't know what else to do.
I can think of two ways. One requires you to change your data structure and the other doesn't.
Without changes:
Sort the user input:
pickedNumbers.sort();
and start comparing. By sorting the values beforehand you know when you can back out and continue with the next set of numbers, i.e. you can back out early and don't have to compare all the values (in the average case).
function wins(picked, winning) {
var winningSet = [];
for (var i = 0; i < winning.length && winningSet.length < 3; i++) {
var set = winning[i];
winningSet = [];
var j = 0;
var k = 0;
while (j < set.length && k < picked.length && winningSet.length < 3) {
if (picked[k] === set[j]) {
winningSet.push(set[j]);
j++; // advance to next element in winning set
} else if (picked[k] > set[j]) {
// continue with the next set
break;
}
// maybe the next element in players picks will match
k++;
}
}
return winningSet.length === 3 ? winningSet : false;
}
The worst case scenario of this solution is O(n*m*l), but since the input is sorted, the average case will be better.
DEMO
With Array#some and Array#every the code becomes much more concise, though it looses the advantage of using sorted input. If your arrays are small it won't make a difference though:
function wins(picked, winning) {
return winning.some(function(set) {
return set.every(function(val) {
return picked.indexOf(val) !== -1;
});
});
}
It also won't give you the actual numbers that matched. The runtime is the same.
The second way would be to build some kind of trie instead of using an array of arrays:
var allwinning = {
'000': {
'010': {
'020': true
},
'100': {
'200': true
},
// ...
}
};
The structure should also be sorted, i.e. the keys of a level are all smaller then the keys of its sublevel etc.
Sort the user input as well and iterate over it. Whenever you found a matching key, you go one level deeper until you have three matches:
function wins(picked, winning) {
var winningSet = [];
for (var i = 0; i < picked.length && winningSet.length < 3; i++) {
if (picked[i] in winning) {
winningSet.push(picked[i]);
winning = winning[picked[i]];
}
}
return winningSet.length === 3 ? winningSet : false;
}
This solution has the worst case scenario of O(n), where n is the number of values the user picked (not taking into account the time it takes to test whether an object contains a specific property name. Often this is assumed to constant).
DEMO

Resources