Skip to content

Commit 5cec17e

Browse files
committed
🌱 初回コミット
0 parents  commit 5cec17e

File tree

12 files changed

+328
-0
lines changed

12 files changed

+328
-0
lines changed

.devcontainer/Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# サービスのビルド環境および実行環境のコンテナ
2+
FROM mcr.microsoft.com/vscode/devcontainers/go:1
3+
WORKDIR /workspace
4+
5+
# 作業ディレクトリ配下をコンテナ側の作業用ディレクトリにコピーする
6+
COPY ./ .

.devcontainer/devcontainer.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "golang-workspace",
3+
"dockerComposeFile": [
4+
"docker-compose.dev.yml"
5+
],
6+
"service": "golang-dev",
7+
"postCreateCommand": [
8+
"bash",
9+
".devcontainer/postCreateCommand.sh"
10+
],
11+
"workspaceFolder": "/workspace"
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
version: "3"
2+
# コンテナプロセスが終了しても作業内容が永続するためのデータボリュームを定義しておく
3+
volumes:
4+
workspace-data:
5+
services:
6+
golang-dev:
7+
# Dockerfileからプロジェクトディレクトリ配下の全てのファイルを参照できるようにプロジェクトディレクトリ直下をcontextに指定する
8+
build:
9+
context: ../
10+
dockerfile: .devcontainer/Dockerfile
11+
volumes:
12+
# 開発に利用するソースコードやビルド結果はホスト側のデータボリュームで管理する
13+
- workspace-data:/workspace
14+
# 開発環境用にプロセスを起動し続ける
15+
tty: true

.devcontainer/postCreateCommand.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/bash
2+
3+
# VSCodeで扱うディレクトリの所有者を Dev Container のデフォルトユーザーである vscode ユーザーに変更する
4+
sudo chown -R vscode:vscode /workspace

.github/workflows/release.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: release
2+
on:
3+
push:
4+
tags:
5+
- "v[0-9]+.[0-9]+.[0-9]+"
6+
jobs:
7+
goreleaser:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v3
12+
with:
13+
fetch-depth: 0
14+
- run: git fetch --force --tags
15+
- name: Setup Go
16+
uses: actions/setup-go@v4
17+
with:
18+
go-version: '1.20'
19+
- name: Run GoReleaser
20+
uses: goreleaser/goreleaser-action@v5
21+
with:
22+
# either 'goreleaser' (default) or 'goreleaser-pro':
23+
distribution: goreleaser
24+
version: latest
25+
args: release --clean
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GROUPING_REPOSITORY_ACCESS_TOKEN }}

.goreleaser.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
project_name: grouping
2+
builds:
3+
- env: [CGO_ENABLED=0]
4+
main: ./cmd/grouping/main.go
5+
goos:
6+
- linux
7+
- windows
8+
- darwin
9+
goarch:
10+
- amd64
11+
- arm64
12+
archives:
13+
- format_overrides:
14+
- goos: windows
15+
format: zip
16+
nfpms:
17+
- maintainer: toriwasa <[email protected]>
18+
description: This is a tool to group sequence of numbers.
19+
homepage: https://github.com/toriwasa/
20+
license: MIT
21+
formats:
22+
- deb
23+
- rpm
24+
- apk

.vscode/launch.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// IntelliSense を使用して利用可能な属性を学べます。
3+
// 既存の属性の説明をホバーして表示します。
4+
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch Package",
9+
"type": "go",
10+
"request": "launch",
11+
"mode": "auto",
12+
"program": "${workspaceFolder}/cmd/grouping/main.go"
13+
, "args": ["-n", "30", "-g", "4"]
14+
}
15+
]
16+
}

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"go.toolsManagement.checkForUpdates": "local",
3+
"go.useLanguageServer": true,
4+
"go.gopath": "/go"
5+
}

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# README
2+
3+
## Overview
4+
- n個の連番をランダムにg個のグループに振り分けるCLIツール
5+
- グループごとに指定した区切り文字で連結した文字列を標準出力する
6+
7+
## Usage
8+
9+
```txt
10+
Show Help
11+
$ grouping --help
12+
13+
Usage:
14+
$ grouping -n <number of elements> -g <number of groups> -d <delimiter> -v
15+
16+
Example:
17+
$ grouping -n 10 -g 4 -d ","
18+
3,4,9
19+
2,5,6
20+
7,8
21+
0,1
22+
```
23+
24+
## How to Build
25+
- VSCode で このリポジトリを開く
26+
- .devcontainer 配下のファイルを利用して開発コンテナを開く
27+
- 起動したコンテナ上のbashで以下のビルドコマンドを実行する
28+
29+
```bash
30+
# Linux向けビルド
31+
go build -o grouping cmd/grouping/main.go
32+
# Winodws向けビルド
33+
GOOS=windows GOARCH=amd64 go build -o grouping.exe cmd/grouping/main.go
34+
```

app/grouping/grouping.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package grouping
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"math/rand"
7+
"sort"
8+
)
9+
10+
// 0から始まるn個の連番をランダムに返すイテレータを返却する
11+
func generateRandomIntIterator(n int) func() (int, error) {
12+
// n個の要素を持つスライスを生成する
13+
seq := make([]int, n)
14+
log.Printf("seq: %v\n", seq)
15+
16+
// 0, 1, 2, .. n の連番を要素として持つようにスライスを初期化する
17+
for i := range seq {
18+
seq[i] = i
19+
}
20+
log.Printf("seq: %v\n", seq)
21+
22+
// スライスの中身をランダムに並び替える
23+
rand.Shuffle(len(seq), func(i, j int) {
24+
seq[i], seq[j] = seq[j], seq[i]
25+
})
26+
log.Printf("seq: %v\n", seq)
27+
28+
// インデックスを管理する変数を定義する
29+
index := -1
30+
// スライスの要素を1つ返す関数を返却する
31+
return func() (int, error) {
32+
index++
33+
if index >= len(seq) {
34+
return 0, fmt.Errorf("index out of range")
35+
}
36+
return seq[index], nil
37+
}
38+
}
39+
40+
// イテレータからn個の値を取り出して昇順ソートしてから指定された区切り文字で分割された文字列にして返却する
41+
func takeNSortedSeparated(iter func() (int, error), n int, delimiter string) (string, error) {
42+
// イテレータからn個の値を取り出してseqスライスに格納する
43+
seq := make([]int, n)
44+
log.Printf("seq: %v\n", seq)
45+
46+
for i := 0; i < n; i++ {
47+
v, err := iter()
48+
if err != nil {
49+
return "", err
50+
}
51+
seq[i] = v
52+
}
53+
log.Printf("seq: %v\n", seq)
54+
55+
// seqスライスを昇順ソートする
56+
sort.Slice(seq, func(i, j int) bool {
57+
return seq[i] < seq[j]
58+
})
59+
log.Printf("seq: %v\n", seq)
60+
61+
// seqスライスの要素を区切り文字で連結した文字列を返却する
62+
s := ""
63+
for i := 0; i < n; i++ {
64+
s += fmt.Sprintf("%d%s", seq[i], delimiter)
65+
}
66+
// 末尾の区切り文字を削除する
67+
s = s[:len(s)-len(delimiter)]
68+
69+
return s, nil
70+
}
71+
72+
// n個の連番をランダムに並び替えた配列をg個のグループに分けて、各グループの要素を区切り文字で分割された文字列にしたイテレータを返却する
73+
func GenerateGroupedRandomSeqIterator(n int, g int, delimiter string) (func() (string, error), error) {
74+
// n は自然数であることを前提とする
75+
if n <= 0 {
76+
return nil, fmt.Errorf("n must be positive, but %d", n)
77+
}
78+
// g は自然数であることを前提とする
79+
if g <= 0 {
80+
return nil, fmt.Errorf("g must be positive, but %d", g)
81+
}
82+
83+
// 最小グループサイズを計算する
84+
minGroupSize := n / g
85+
// 最大要素数のグループ数を計算する
86+
maxElementsGroupCount := n % g
87+
log.Printf("minGroupSize: %d\n", minGroupSize)
88+
log.Printf("maxElementsGroupCount: %d\n", maxElementsGroupCount)
89+
90+
iter := generateRandomIntIterator(n)
91+
92+
outputGroupCount := -1
93+
// グループの数だけ区切り文字で連結した文字列を返すイテレータを返却する
94+
return func() (string, error) {
95+
outputGroupCount++
96+
// イテレータのループ上限はグループ数に等しい
97+
if outputGroupCount >= g {
98+
return "", fmt.Errorf("outputGroupCount out of range")
99+
}
100+
101+
// 1グループあたり要素数のデフォルトは最小グループサイズ
102+
groupSize := minGroupSize
103+
// 最大要素数のグループ数に達するまでは、1グループあたり要素数を1つ増やす
104+
if outputGroupCount < maxElementsGroupCount {
105+
groupSize++
106+
}
107+
// 1グループ分の文字列要素を取得して返却する
108+
s, err := takeNSortedSeparated(iter, groupSize, delimiter)
109+
if err != nil {
110+
return "", err
111+
}
112+
return s, nil
113+
}, nil
114+
}

0 commit comments

Comments
 (0)