Skip to content

Conversation

@rihib
Copy link
Owner

@rihib rihib commented Dec 17, 2024

*/
func moveZeroes(nums []int) {
zeroIndex := 0
for i, n := range nums {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zeroIndexという名前で何を表す変数なのか(indexである以上のことが)分からない気はしました。
iとかjとかにしちゃって、コメントで補足するほうが読みやすいと思いました
(個人的にこの問題はループ不変条件が何かを意識するのが大事な気がしており、今回であればzeroIndexより左と、zeroIndexからiまでが各ループの終わりで何が入っているか書いてあると分かりやすいかなと思います)

if n == 0 {
continue
}
nums[zeroIndex], nums[i] = nums[i], nums[zeroIndex]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これ C++ だと zeroIndex == i の場合は未定義動作にあたるかと思いますが、Go では大丈夫でしょうか。

この質問は、本当に不安に思っているというよりは、言語仕様を調べたことがありますか、それとも漫然と経験上書いていますか、という質問です。

私は練習の仕方は自由度があってよいと思っていますが、参考までに練習の目的については下のように思っています。
https://docs.google.com/document/d/1bjbOSs-Ac0G_cjVzJ2Qd8URoU_0BNirZ8utS3CUAeLE/edit?tab=t.0

Copy link
Owner Author

@rihib rihib Dec 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。多重代入については以前に調べたことがあり、この場合は左辺と右辺の値が評価されてから代入が行われると書かれているため(https://go.dev/ref/spec#Assignment_statements )、問題ないという認識を持っています。

ただしマニュアルを読みたくなるという反応がきちんと自分の中に備わっているかどうかは微妙な部分があるので、そういった点は気をつけながら取り組んでいかないとなと思います。

zeroIndexをインクリメントすることで、zeroIndexの左側に非ゼロの要素を集め、
右側にゼロを集めるという感じ。

境界というのを明確にしたいのであればstartZeroIndexとかでもいいかも。またはzeroIndexだとインデックスの値自体が0なのかという誤解を引き起こす恐れがあるので、indexOfStartZeroIndexとかでもいいかもしれない。ただ全体の行数に対して変数名が冗長すぎる気がしたので今回はzeroIndexにした。

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loop内でzeroIndexが0以外を指していることもあるので、役割と名前があってなさそうです。

あと、zeroIndexは境界の役割というコメントがありましたが、zeroIndexの動きを言葉で表現しようとすると境界よりも複雑なことをしてて、fhiyoのレビューのように、コメントで補足してもらうとわかりやすいと思いました

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

最初の0が見つかるまでの間はzeroIndex == iなのでその間はスワップ自体はしていますが自分自身をスワップしているだけで、結果的には単にzeroIndexとiをそれぞれインクリメントしているだけなので何もしていないようなものかなと思っています。

最初の0が見つかったあとは0がだんだん後ろに流れていくという動きになります。
例(太字がzeroIndexの場所):[1, 0, 0, 2, 3, 4]→[1, 2, 0, 0, 3, 4]→[1, 2, 3, 0, 0, 4]→[1, 2, 3, 4, 0, 0]

そういう意味でzeroIndexがゼロ値を指していて、非ゼロとゼロの境界になると説明した感じです。なのでそこまでzeroIndex自体は複雑なことはやっていないかなと思っているのですが、最初のゼロが見つかるまでの動きについては確かにちょっと混乱を招くので、コメントをつけた方がいいかなと思いました。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私の気持ちとしては、これは配列とサイズの組み合わせで追記をしている(vector push_back の動作)ものの変形と感じるので。「いくつ非ゼロが見つかったか」というように見ています。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かにそう考えると最初の0が見つかるまでの間の挙動もわかりやすくなりそうですね

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうすると、あとから0を埋めるというのも一つです。
C++ の remove_if と fill という組み合わせですね。

速度はどっちが速いか分からないです。複雑な書き込みのほうが遅いかも?

@nittoco
Copy link

nittoco commented Dec 27, 2024

一つなんとなく考えたこととして、

nums[zeroIndex], nums[i] = nums[i], nums[zeroIndex]

ではなく、

nums[zeroIndex] = nums[i]
nums[i] = 0

としてしまう案もありますね。(結局同じですが、意図がわかりやすいきがしてます)

@rihib
Copy link
Owner Author

rihib commented Dec 28, 2024

@nittoco そうすると自分自身をスワップする段階のときにおかしくなりませんか?

@nittoco
Copy link

nittoco commented Dec 28, 2024

あ、これ最初の0が出てくるまでは実質swapしてないんですね(ちゃんと動作が追えてなかったです)。ありがとうございます。
上のを書くならif zeroIndex < i とかが必要ですね。
それか、Iwasaさんのコメントにある通りzeroIndexが名前と合ってないので、

while i < len(nums) and nums[i] != 0:
    i += 1

みたいに最初にしちゃう手もありますね。

@rihib rihib merged commit 7931676 into main Feb 24, 2025
@rihib rihib deleted the move_zeroes branch February 24, 2025 07:26
rihib added a commit that referenced this pull request Mar 31, 2025
rihib added a commit that referenced this pull request Mar 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants