How to find out element position in slice?

PositionGoSlice

Position Problem Overview


How does one determine the position of an element present in slice?

I need something like the following:

type intSlice []int

func (slice intSlice) pos(value int) int {
	for p, v := range slice {
		if (v == value) {
			return p
		}
	}
	return -1
}

Position Solutions


Solution 1 - Position

Sorry, there's no generic library function to do this. Go doesn't have a straight forward way of writing a function that can operate on any slice.

Your function works, although it would be a little better if you wrote it using range.

If you happen to have a byte slice, there is bytes.IndexByte.

Solution 2 - Position

You can create generic function in idiomatic go way:

func SliceIndex(limit int, predicate func(i int) bool) int {
    for i := 0; i < limit; i++ {
        if predicate(i) {
            return i
        }
    }
    return -1
}

And usage:

xs := []int{2, 4, 6, 8}
ys := []string{"C", "B", "K", "A"}
fmt.Println(
    SliceIndex(len(xs), func(i int) bool { return xs[i] == 5 }),
    SliceIndex(len(xs), func(i int) bool { return xs[i] == 6 }),
    SliceIndex(len(ys), func(i int) bool { return ys[i] == "Z" }),
    SliceIndex(len(ys), func(i int) bool { return ys[i] == "A" }))

Solution 3 - Position

You could write a function;

func indexOf(element string, data []string) (int) {
   for k, v := range data {
       if element == v {
           return k
       }
   }
   return -1	//not found.
}

This returns the index of a character/string if it matches the element. If its not found, returns a -1.

Solution 4 - Position

There is no library function for that. You have to code by your own.

Solution 5 - Position

You can just iterate of the slice and check if an element matches with your element of choice.

func index(slice []string, item string) int {
    for i := range slice {
	    if slice[i] == item {
		    return i
    	}
	}
    return -1
}

Solution 6 - Position

Another option is to sort the slice using the sort package, then search for the thing you are looking for:

package main

import (
	"sort"
	"log"
	)

var ints = [...]int{74, 59, 238, -784, 9845, 959, 905, 0, 0, 42, 7586, -5467984, 7586}

func main() {
    	data := ints
    	a := sort.IntSlice(data[0:])
    	sort.Sort(a)
    	pos := sort.SearchInts(a, -784)
    	log.Println("Sorted: ", a)
    	log.Println("Found at index ", pos)
}

prints

2009/11/10 23:00:00 Sorted:  [-5467984 -784 0 0 42 59 74 238 905 959 7586 7586 9845]
2009/11/10 23:00:00 Found at index  1

This works for the basic types and you can always implement the sort interface for your own type if you need to work on a slice of other things. See <http://golang.org/pkg/sort>

Depends on what you are doing though.

Solution 7 - Position

Go supports generics as of version 1.18, which allows you to create a function like yours as follows:

func IndexOf[T comparable](collection []T, el T) int {
	for i, x := range collection {
		if x == el {
			return i
		}
	}
	return -1
}

If you want to be able to call IndexOf on your collection you can alternatively use @mh-cbon's technique from the comments.

Solution 8 - Position

I had the same issue few months ago and I solved in two ways:

First method:

func Find(slice interface{}, f func(value interface{}) bool) int {
	s := reflect.ValueOf(slice)
	if s.Kind() == reflect.Slice {
		for index := 0; index < s.Len(); index++ {
			if f(s.Index(index).Interface()) {
				return index
			}
		}
	}
	return -1
}

Use example:

type UserInfo struct {
	UserId      	int
}

func main() {
	var (
		destinationList []UserInfo
		userId		int = 123
	)
	
	destinationList = append(destinationList, UserInfo { 
		UserId      	: 23,
	}) 
	destinationList = append(destinationList, UserInfo { 
		UserId      	: 12,
	}) 
	
	idx := Find(destinationList, func(value interface{}) bool {
		return value.(UserInfo).UserId == userId
	})
	
	if idx < 0 {
		fmt.Println("not found")
	} else {
		fmt.Println(idx)	
	}
}

Second method with less computational cost:

func Search(length int, f func(index int) bool) int {
	for index := 0; index < length; index++ {
		if f(index) {
			return index
		}
	}
	return -1
}

Use example:

type UserInfo struct {
	UserId      	int
}

func main() {
	var (
		destinationList []UserInfo
		userId		int = 123
	)
	
	destinationList = append(destinationList, UserInfo { 
		UserId      	: 23,
	}) 
	destinationList = append(destinationList, UserInfo { 
		UserId      	: 123,
	}) 
	
	idx := Search(len(destinationList), func(index int) bool {
		return destinationList[index].UserId == userId
	})
	
	if  idx < 0 {
		fmt.Println("not found")
	} else {
		fmt.Println(idx)	
	}
}

Solution 9 - Position

Another option if your slice is sorted is to use SearchInts(a []int, x int) int which returns the element index if it's found or the index the element should be inserted at in case it is not present.

s := []int{3,2,1}
sort.Ints(s)
fmt.Println(sort.SearchInts(s, 1)) // 0
fmt.Println(sort.SearchInts(s, 4)) // 3

https://play.golang.org/p/OZhX_ymXstF

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOCyrilView Question on Stackoverflow
Solution 1 - PositionEvan ShawView Answer on Stackoverflow
Solution 2 - PositionHodzaView Answer on Stackoverflow
Solution 3 - PositionPodTech.ioView Answer on Stackoverflow
Solution 4 - PositionalessandroView Answer on Stackoverflow
Solution 5 - Positionuser60679View Answer on Stackoverflow
Solution 6 - PositionrobothorView Answer on Stackoverflow
Solution 7 - PositionLevi BotelhoView Answer on Stackoverflow
Solution 8 - PositionomottoView Answer on Stackoverflow
Solution 9 - PositionAlan SerebView Answer on Stackoverflow