1

I am making a basic program in Golang which outputs the number of files in your current directory and how many lines of code each file contains:

I am trying now to group the files that have the same extension and I run into problems. so, what I did is declaring a map of strings as keys and a slice of strings as value:

to store the extname as a key with its files in that slice

var m = make(map[string][]string)

I first receive in "group" function a slice of files read by the program (q argument) which looks like this:

[.gitignore README.md cmd\root.go example.go eyeball.exe go.mod go.sum main.go utils\utils.go]

Then I operate on that slice of files:



func group(q []string) {

    var ext string
    var checkedext []string

    for _, val := range q {
        ext = strings.Split(val, ".")[1]
        for _, foo := range q {
            secext := strings.Split(foo, ".")[1]
            if ext == secext {
                if !contains(checkedext, ext) {
                    addtogroup(ext, foo)
                    checkedext = append(checkedext, ext)
                }
            }
        }
    }
    fmt.Println(m)

}

func contains(s []string, item string) bool {
    for _, el := range s {
        if el == item {
            return true
        }
    }
    return false
}

var m = make(map[string][]string)


func addtogroup(ext, file string) {

    var subgroup []string
    if val, ok := m[ext]; ok {
       val = append(val, file)
    } else {
        subgroup = append(subgroup, file)
        m[ext] = subgroup
    }
}

and when I print the map It outputs this:

map[exe:[eyeball.exe] gitignore:[.gitignore] go:[cmd\root.go] md:[README.md] mod:[go.mod] sum:[go.sum]]

However, the above output is wrong because I have 3 .go files.

I know that range iterates through a copy of the map and I can't reference it by pointer because the map is a reference itself, I can't find a way around it, I thought of making this:

var m = make(map[string]*Data)

but I don't know If it's the best thing to do or not

I tried hard to explain what I want my program to do and what it does instead so, If I am missing any details just point me out.

icza
  • 389,944
  • 63
  • 907
  • 827

1 Answers1

2

The problem is that when you add an element to a slice (that's inside the map), you have to reassign the result slice, because append() returns a new slice header that contains the appended items:

if val, ok := m[ext]; ok {
   val = append(val, file)
    m[ext] = val
} else {
    // ...
}

Or simply:

m[ext] = append(m[ext], file)

This also handles if ext is not yet in the map, because then m[ext] will be the zero value of the value type (which is []string), and the zero value is the nil slice. You are allowed to append to the nil slice.

Also to get the extension, use filepath.Ext().

Your group() function can be as simple as this:

func group(names []string) map[string][]string {
    m := map[string][]string{}
    for _, name := range names {
        ext := filepath.Ext(name)
        ext = strings.TrimPrefix(ext, ".")
        m[ext] = append(m[ext], name)
    }
    return m
}

Testing it:

fmt.Println(group([]string{"x\\a.txt", "b.txt", "c.go"}))

fmt.Println(group([]string{"a.go", "xy\\b.go", "c.txt"}))

Which outputs (try it on the Go Playground):

map[go:[c.go] txt:[x\a.txt b.txt]]
map[go:[a.go xy\b.go] txt:[c.txt]]

See related questions:

How to update map values in Go

How to categorize list of objects based on a parameter

icza
  • 389,944
  • 63
  • 907
  • 827
  • Look how many lines of code I wrote to get this basic feature done and to your solution :) – Mohamed Tarek Nov 01 '20 at 17:12
  • Can I do it using the struct (Data) I showed earlier in the question If so, could you tell me how? and If it will be a better approach or not? – Mohamed Tarek Nov 01 '20 at 17:15
  • @MohamedTarek You didn't show how you image that, but a slice is a small struct that contains a pointer to a backing array, so it's similar to using `*Data`. I think my presented solution is pretty clear, compact and efficient. I don't know exactly what more you'd want to do with `Data`. – icza Nov 01 '20 at 17:22