paiza の基礎問題を Go で解いて気づいた Go らしさ

2 min read 2

たまたま見かけた以下の問題を解きました。

https://paiza.jp/works/mondai/skillcheck_archive/word-count?language_uid=go

問題としてはかなり簡単なものですが、 「Go らしさ」が伝わって面白かったので書きます。
Ruby との比較もあるよ💎

問題

スペースで区切られた英単語列が与えられます。
英単語列に含まれる英単語の出現回数を出現した順番に出力してください。
red green blue blue green blue
 
=> 結果
red 1
green 2
blue 3
Apple Apricot Orange Cherry Apple Orange Cherry Orange

=> 結果
Apple 2
Apricot 1
Orange 3
Cherry 2

解答

package main

import (
	"fmt"
	"strings"
)

func main() {
	sample1 := "red green blue blue green blue"
	sample2 := "Apple Apricot Orange Cherry Apple Orange Cherry Orange"

	execute(sample1)
	execute(sample2)
}

func execute(s string) {
	fmt.Println("==================================")

	strs := strings.Split(s, " ")
	uniqStrs := uniq(strs)

	result := make(map[string]int)

	for _, v := range strs {
		count := strings.Count(s, v)
		result[v] = count
	}
	display(uniqStrs, result)
}

func display(uniqSlice []string, result map[string]int) {
	for _, key := range uniqSlice {
		fmt.Printf("%s %d\n", key, result[key])
	}
}

func uniq(slice []string) []string {
	m := make(map[string]bool)
	uniqSlice := make([]string, 0)

	for _, v := range slice {
		if _, ok := m[v]; !ok {
			m[v] = true
			uniqSlice = append(uniqSlice, v)
		}
	}
	return uniqSlice
}

解説

シンプルな問題ですが、コードの量が多いのが印象的です🧐

スライス要素の重複を削除したいだけですが、 uniq のような関数が必要になります。
この書き方は Go の中では一般的なようで、適当な map と最終的な結果を入れるスライスを作成して range ループを回すということらしいです。

Go はやはり痒いところに手が届くような関数は用意されておらず、ある程度自分で実装する必要があります。
そういう時には、イディオム的な書き方を知っておくと便利だと思います。

参考までにこの問題を ruby で解くと以下のようになりました。

def main(str)
  p "========================================================"
  arr = str.split(" ")
  uniq = arr.uniq

  result = uniq.each_with_object({}) do |s, h|
    h[s] = str.scan(s).length
  end

  result.each do |k, v|
    p "#{k} #{v}"
  end
end

sample1 = "red green blue blue green blue"
sample2 = "Apple Apricot Orange Cherry Apple Orange Cherry Orange"

main(sample1)
main(sample2)

単純な比較はできませんが、コード量でいくと ruby の方が随分少ないことが分かります。
配列の重複排除は uniq で1発ですし、 each_with_object も便利です。


手を動かして、目指せ Gopher 👨‍💻