How to get single items count in a slice with go? - go

For example, this is a slice:
[1, 2, 3, 3, 4]
want to get single data 1, 2, 4 's count and return count = 3.
Maybe remove duplicate items(include itself) is an idea, but didn't find suitalbe method.
What I tried:
func removeDuplicateItems() {
intSlice := []int{1, 2, 3, 3, 4}
fmt.Println(intSlice)
keys := make(map[int]bool)
list := []int{}
for _, entry := range intSlice {
if _, value := keys[entry]; !value {
keys[entry] = true
list = append(list, entry)
}
}
fmt.Println(list)
}
Got
[1 2 3 3 4]
[1 2 3 4]

I just changed your function a little bit:
func removeDuplicateItems() {
intSlice := []int{1, 2, 3, 3, 4}
fmt.Println(intSlice)
keys := make(map[int]int)
list := []int{}
for _, entry := range intSlice {
keys[entry]++
}
for k, v := range keys {
if v == 1 {
list = append(list, k)
}
}
fmt.Println(list)
}
https://play.golang.org/p/ESFLhC4VC-l
At this point the list is not sorted. If you want to sort your list afterward you need to use the sortpackage.

I suppose a really easy & quick way to get the count of unique values would be to use a map:
data := map[int]bool{}
cnt := 0 // count of unique values
for _, i := range intSlice {
if dup, ok := data[i]; !ok {
// we haven't seen value i before, assume it's unique
data[i] = false // add to map, mark as non-duplicate
cnt++ // increment unique count
} else if !dup {
// we have seen value i before, but this is only the second time
cnt-- // unique count goes down here
data[i] = true // mark this value as known duplicate
}
}
At the end of this loop, you'll have cnt with the count of unique values, and you can iterate the map data for all keys with value false to get the unique values that you found in the slice. All keys combined basically are the values in the slice, de-duplicated.

Related

how to get lonely value from a slice golang [duplicate]

This question already has answers here:
How to remove duplicates strings or int from Slice in Go
(12 answers)
How to delete duplicates of an item from a slice?
(3 answers)
how to delete Duplicate elements between slices on golang
(1 answer)
Closed 10 months ago.
I want to create a function that can retrieve data that has no duplicates from a slice
an example of a slice that will be processed:
number1 := []int{3,4,5,4,3}
number2 := []int{3,4,5,6,4,3}
expected result :
res1 = []int{5}
res2 = []int{5,6}
i have do something like this
func unique(arg []int) []int {
var inResult = make(map[int]bool)
var result []int
for _, value := range arg {
if _, ok := inResult[value]; !ok {
inResult[value] = true
result = append(result, value)
} else {
inResult[value] = false
}
}
fmt.Println(inResult)
return result
}
func main() { arg := []int{6, 6, 7, 1, 2, 3, 4, 5, 3, 2, 1}
res := unique(arg)
fmt.Println(res)
}
how to get the key from map where the value is true?
map[1:false 2:false 3:false 4:true 5:true 6:false 7:true]
[6 7 1 2 3 4 5]
You can filter out the keys like this.
Remove the following line in if block. It should be done after the complete iteration.
result = append(result, value)
Filter the keys with having true value before returning result.
for key, value := range inResult {
if value {
result = append(result, key)
}
}
Go Playground

Concat two maps in golang

I know about the append function in golang, but is there a similar function to append two maps.
slice1 := []string{"hello"}
slice2 := []string{"world"}
combined := append(slice1, slice2...)
I tried to do the same thing with maps, but it gave me this error:
first argument to append must be slice; have map[string]string
Is therea a method to append two maps in go?
Just write a loop or two.
map1 := map[string]int{
"one": 1,
"two": 2,
}
map2 := map[string]int{
"uno": 1,
"dos": 2,
}
combined := map[string]int{}
for k, v := range map1 {
combined[k] = v
}
for k, v := range map2 {
combined[k] = v
}
fmt.Println(combined) // map[dos:2 one:1 two:2 uno:1]
Try it on the playground.
Order matters, of course, if the two maps have overlapping sets of keys.

Deleting multiple values from a map in Go at the same time within a loop

I'm trying to delete multiple values from my map[string][]interface{}
I am using the strings.Split function to separate each value i wish to delete, and then looping through them.
I have managed to get it so i can delete index values 0 and 1, however, 1,2 would delete index value 1, but error on index 2.
I have also managed to get it to delete a single value
My thought process was that if I can get it to delete just one value (any index i enter, inc first and last index), then i could use a loop to loop through, and delete the rest.
Everything is stored in the below:
package db
var DataStore map[string][]interface{}
The function
func HandleDelete(w http.ResponseWriter, k, v string) {
It takes the value you wish to delete in as a parameter (and the key, but that's fully functional)
The block of code the issue resides in
The loop starts at the end of the map slice, so when you remove index value 5 for example, 4 is still 4. Whereas if I go the other way, if i delete 5, 6 then becomes index 5. So 5,6 being deleted would effectively mean 5,7 is being deleted.
for i := len(db.DataStore) - 1; i >= 0; i-- {
for _, idxvalue := range values {
val, err := strconv.Atoi(idxvalue)
if err != nil {
log.Fatal(err)
return
}
dbval := db.DataStore[k][val]
if i == val {
if len(db.DataStore[k])-1 == i { //the length goes 1,2,3,4... the index goes 0,1,2,3 - therefore length -1, would be 3 - deletes the last index value
db.DataStore[k] = db.DataStore[k][:i]
} else { //delete everything else
db.DataStore[k] = append(db.DataStore[k][:i], db.DataStore[k][i+1:]...)
}
//when you delete the last value in that key, delete the key.
/*if len(db.DataStore[k]) == 0 {
delete(db.DataStore, k)
}*/
fmt.Fprintf(w, "Key: %v, Value: %v was deleted successfully", k, dbval)
}
}
}
I have tried both loops as below:
for i := len(db.DataStore) - 1; i >= 0; i-- {
Of course the reason the below didn't work, is because you're getting the length, before the loop (in the func body) which won't change after each iteration.
idx := len(db.DataStore) - 1
for i := idx; i >= 0; i-- {
The below code is to delete the index entered (this works with a single value)
if len(db.DataStore[k])-1 == i { //the length goes 1,2,3,4... the index goes 0,1,2,3 - therefore length -1, would be 3 - deletes the last index value
db.DataStore[k] = db.DataStore[k][:i]
} else { //delete everything else
db.DataStore[k] = append(db.DataStore[k][:i], db.DataStore[k][i+1:]...)
}
I expect the out put of '2,1' to delete index 1 and 2, but the actual input is that it just deletes index 1.
For example,
package main
import "fmt"
// Delete m k v elements indexed by d.
func deleteMKVD(m map[string][]interface{}, k string, d []int) {
v, ok := m[k]
if !ok {
return
}
for _, i := range d {
if 0 <= i && i < len(v) {
v[i] = nil
}
}
lw := 0
for i := range v {
if v[i] != nil {
lw++
}
}
if lw == 0 {
delete(m, k)
return
}
w := make([]interface{}, 0, lw)
for i := range v {
if v[i] != nil {
w = append(w, v[i])
}
}
m[k] = w
}
func main() {
m := map[string][]interface{}{
"k0": {"v0", "v1", "v2", "v3"},
}
fmt.Println(m)
deleteMKVD(m, "k0", []int{0, 3})
fmt.Println(m)
deleteMKVD(m, "k0", []int{1, 0})
fmt.Println(m)
}
Playground: https://play.golang.org/p/biEAxthTaj8
Output:
map[k0:[v0 v1 v2 v3]]
map[k0:[v1 v2]]
map[]
I think your problem is actually to remove elements from an array with an array of indices.
The easy fix here would be:
1) Find all the indices with certain k, make it an array(vals []int).
2) Sort this array int descendent. and iterate this array to delete
3) Then iterate this array to delete the elements.
In this way, every time you delete an element, it won't touch other elements' indices.
It may not be most efficient, but it would be a quick fix.
BTW, I think for i := len(db.DataStore) - 1; i >= 0; i--is not what you want.
If I understand correctly, this code here seems to make sure the val is the largest index in those indices.
So instead of write i:=len(db.DataStore) - 1, you actually need i:=len(db.DataStore[k])-1

How to get rid of zero value in a int slice in Go?

I am trying to find even numbers in a list of numbers, here is my attempt:
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7}
res := []int{}
for n := range nums {
if n%2 == 0 {
res = append(res, n)
}
}
fmt.Println(res)
}
It seems straightforward; however, when I run the program, I got the result
[0 2 4 6]
Where does the zero come from? It must be from the empty slice res. How can I get rid of this zero?
for n := range nums {
// ...
}
n is not the elements of the nums slice, it is the index. So basically you tested and added the indices of the elements to your res result slice.
Instead do this:
for _, n := range nums {
// ...
}
With this change, output will be (try it on the Go Playground):
[2 4 6]
This is detailed in Spec: For statements, For statements with range clause:
For each iteration, iteration values are produced as follows if the respective iteration variables are present:
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E

How to remove items from a slice while ranging over it?

What is the best way to remove items from a slice while ranging over it?
For example:
type MultiDataPoint []*DataPoint
func (m MultiDataPoint) Json() ([]byte, error) {
for i, d := range m {
err := d.clean()
if ( err != nil ) {
//Remove the DP from m
}
}
return json.Marshal(m)
}
As you have mentioned elsewhere, you can allocate new memory block and copy only valid elements to it. However, if you want to avoid the allocation, you can rewrite your slice in-place:
i := 0 // output index
for _, x := range s {
if isValid(x) {
// copy and increment index
s[i] = x
i++
}
}
// Prevent memory leak by erasing truncated values
// (not needed if values don't contain pointers, directly or indirectly)
for j := i; j < len(s); j++ {
s[j] = nil
}
s = s[:i]
Full example: http://play.golang.org/p/FNDFswPeDJ
Note this will leave old values after index i in the underlying array, so this will leak memory until the slice itself is garbage collected, if values are or contain pointers. You can solve this by setting all values to nil or the zero value from i until the end of the slice before truncating it.
I know its answered long time ago but i use something like this in other languages, but i don't know if it is the golang way.
Just iterate from back to front so you don't have to worry about indexes that are deleted. I am using the same example as Adam.
m = []int{3, 7, 2, 9, 4, 5}
for i := len(m)-1; i >= 0; i-- {
if m[i] < 5 {
m = append(m[:i], m[i+1:]...)
}
}
There might be better ways, but here's an example that deletes the even values from a slice:
m := []int{1,2,3,4,5,6}
deleted := 0
for i := range m {
j := i - deleted
if (m[j] & 1) == 0 {
m = m[:j+copy(m[j:], m[j+1:])]
deleted++
}
}
Note that I don't get the element using the i, d := range m syntax, since d would end up getting set to the wrong elements once you start deleting from the slice.
Here is a more idiomatic Go way to remove elements from slices.
temp := s[:0]
for _, x := range s {
if isValid(x) {
temp = append(temp, x)
}
}
s = temp
Playground link: https://play.golang.org/p/OH5Ymsat7s9
Note: The example and playground links are based upon #tomasz's answer https://stackoverflow.com/a/20551116/12003457
One other option is to use a normal for loop using the length of the slice and subtract 1 from the index each time a value is removed. See the following example:
m := []int{3, 7, 2, 9, 4, 5}
for i := 0; i < len(m); i++ {
if m[i] < 5 {
m = append(m[:i], m[i+1:]...)
i-- // -1 as the slice just got shorter
}
}
I don't know if len() uses enough resources to make any difference but you could also run it just once and subtract from the length value too:
m := []int{3, 7, 2, 9, 4, 5}
for i, s := 0, len(m); i < s; i++ {
if m[i] < 5 {
m = append(m[:i], m[i+1:]...)
s--
i--
}
}
Something like:
m = append(m[:i], m[i+1:]...)
You don't even need to count backwards but you do need to check that you're at the end of the array where the suggested append() will fail. Here's an example of removing duplicate positive integers from a sorted list:
// Remove repeating numbers
numbers := []int{1, 2, 3, 3, 4, 5, 5}
log.Println(numbers)
for i, numbersCount, prevNum := 0, len(numbers), -1; i < numbersCount; numbersCount = len(numbers) {
if numbers[i] == prevNum {
if i == numbersCount-1 {
numbers = numbers[:i]
} else {
numbers = append(numbers[:i], numbers[i+1:]...)
}
continue
}
prevNum = numbers[i]
i++
}
log.Println(numbers)
Playground: https://play.golang.org/p/v93MgtCQsaN
I just implement a method which removes all nil elements in slice.
And I used it to solve a leetcode problems, it works perfectly.
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeNil(lists *[]*ListNode) {
for i := 0; i < len(*lists); i++ {
if (*lists)[i] == nil {
*lists = append((*lists)[:i], (*lists)[i+1:]...)
i--
}
}
}
You can avoid memory leaks, as suggested in #tomasz's answer, controlling the capacity of the underlying array with a full slice expression. Look at the following function that remove duplicates from a slice of integers:
package main
import "fmt"
func removeDuplicates(a []int) []int {
for i, j := 0, 1; i < len(a) && j < len(a); i, j = i+1, j+1 {
if a[i] == a[j] {
copy(a[j:], a[j+1:])
// resize the capacity of the underlying array using the "full slice expression"
// a[low : high : max]
a = a[: len(a)-1 : len(a)-1]
i--
j--
}
}
return a
}
func main() {
a := []int{2, 3, 3, 3, 6, 9, 9}
fmt.Println(a)
a = removeDuplicates(a)
fmt.Println(a)
}
// [2 3 3 3 6 9 9]
// [2 3 6 9]
For reasons #tomasz has explained, there are issues with removing in place. That's why it is practice in golang not to do that, but to reconstruct the slice. So several answers go beyond the answer of #tomasz.
If elements should be unique, it's practice to use the keys of a map for this. I like to contribute an example of deletion by use of a map.
What's nice, the boolean values are available for a second purpose. In this example I calculate Set a minus Set b. As Golang doesn't have a real set, I make sure the output is unique. I use the boolean values as well for the algorithm.
The map gets close to O(n). I don't know the implementation. append() should be O(n). So the runtime is similar fast as deletion in place. Real deletion in place would cause a shifting of the upper end to clean up. If not done in batch, the runtime should be worse.
In this special case, I also use the map as a register, to avoid a nested loop over Set a and Set b to keep the runtime close to O(n).
type Set []int
func differenceOfSets(a, b Set) (difference Set) {
m := map[int]bool{}
for _, element := range a {
m[element] = true
}
for _, element := range b {
if _, registered := m[element]; registered {
m[element] = false
}
}
for element, present := range m {
if present {
difference = append(difference, element)
}
}
return difference
}
Try Sort and Binary search.
Example:
package main
import (
"fmt"
"sort"
)
func main() {
// Our slice.
s := []int{3, 7, 2, 9, 4, 5}
// 1. Iterate over it.
for i, v := range s {
func(i, v int) {}(i, v)
}
// 2. Sort it. (by whatever condition of yours)
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j]
})
// 3. Cut it only once.
i := sort.Search(len(s), func(i int) bool { return s[i] >= 5 })
s = s[i:]
// That's it!
fmt.Println(s) // [5 7 9]
}
https://play.golang.org/p/LnF6o0yMJGT

Resources