😎
paiza の基礎問題を Go で解いて気づいた 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 👨💻
Discussion
Go のマップ や Ruby のハッシュを使えば、自然に重複排除ができるので、わざわざ uniq する必要はありません。
Ruby 版は以下のようになります。
Go 版は以下の通りです。
Go の map はキーの順序を保持しないので、uniq_words が順序保持のために必要になりますが、
それ以外は Ruby と比べても、多少長い程度で、十分シンプルだと思います。
コメントありがとうございます!
手元で試せていませんが、そういう書き方もあるのですね。
勉強になりました、ありがとうございます😊