NEKO BLOG

年別に記事を並べたいのに、なぜ先に全記事をsortするのか

このブログは、Codexを利用して構築しているのですが、 その時に生成されたコードが初見で????の嵐でした。

読み解いていくと「なるほどな〜」となったので紹介していこうと思います。

きっかけ

前提として、トップ画面やタグ一覧などの一覧画面では、年ごとに降順(新しいものが上に)なる形で表示をしたかった。

イメージとしてはこんな感じ。

plain text

2026
  9/13 generateStaticParams...
  9/12 Next.jsのSSG...
  8/30 Docker...

2025
  12/10 ...
  10/05 ...

コードが生成される前の私の思考では、

  • Notion APIで取得した記事一覧を年ごとにグルーピングして
  • それぞれ降順に並び替える

程度でいけるかなーと考えていました。

実際のコード

で。出てきたコードがこちら。

typescript

export function getPostsByYear(posts: readonly PostSummary[]) {
	const postsByYear = new Map<string, PostSummary[]>()
	for (const post of [...posts].sort((firstPost, secondPost) =>
	 secondPost.publishedAt.localeCompare(firstPost.publishedAt)
  )) {
   const year = getYear(post.publishedAt)
   const postsInYear = postsByYear.get(year) ?? []

   postsInYear.push(post)
   postsByYear.set(year, postsInYear)
  }
  return [...postsByYear.entries()].sort(([firstYear], [secondYear]) =>
	  secondYear.localeCompare(firstYear)
	)
}

…なんて???

確かに私はアルゴリズム知識がポンコツだけれども。 これはあまりに可読性が悪すぎやしないか? そしてこれは何をしているんだ??何したいんだ??

処理を読み解く

まずは postsByYear 、これはいいかな。年ごとにMapで記事情報を分けるみたいです。

string側に年、PostSummary[]側に記事情報を格納する。

最後に[...postsByYear.entries()].sort で年ごとの降順に並び替えてる。 これはまあいいでしょう。

typescript

const postsByYear = new Map<string, PostSummary[]>()

問題はこれ。

何を回してるんだ、お前は??? というかfor文を3行に跨ぐとか何事か。

typescript

for (const post of [...posts].sort((firstPost, secondPost) =>
	 secondPost.publishedAt.localeCompare(firstPost.publishedAt)
  ))

と、逃走しそうになりましたが。 sortの中身がややこしく見えるだけで、要は記事一覧 posts を並び替えている。

ふむ。で??

2番目の publishedAt と1番目の publishedAtlocaleCompareで比較している。 localeCompare??String.prototype.localeCompare() 、、、いやStringの比較かい!

developer.mozilla.orghttps://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

一人ツッコミはここまでにしておき。

このブログでは、Notionの日付プロパティから取得したデータはYYYY-MM-DD形式に変換しています。 例えばこんな感じ。

typescript

2026-09-13
2026-09-12
2026-08-30
...

この状態でlocaleCompare をかけると、文字列として辞書順に比較をする。 今回比較するのは年・月・日の順で桁数が揃った形式なので、 これを2番目が先、1番目が後、すなわち降順に並び替えているようです。

あとは publishedAtを降順で並び替えたpostsを順番に取り出し、 年を取得して年ごとMapに詰め込む。

typescript

   const year = getYear(post.publishedAt)
   const postsInYear = postsByYear.get(year) ?? []

   postsInYear.push(post)
   postsByYear.set(year, postsInYear)

なるほどね。。。(ここまで来るのが長かった、、、)

ここに入っている postsByYear はこんな感じ。

plain text

"2026" → [09-13の記事, 09-12の記事, 08-30の記事,...]
"2025" → [12-10の記事, 10-15の記事,...]

・・・おお。 最近投稿した記事が上に、年ごとに記事がグルーピングされている・・・! 先に全体を並べておけば、年別のグルーピング後にソートし直さなくていいのか!

妙なAHA体験ができてしまった笑

今回の学び

先にデータ全体の順序を整えておけば、後の処理でもその順序を利用できる。

こういうデータの並べ替えやグルーピングは、単にコードを読めるだけでなく、 「どの順番で処理すれば後の処理が楽になるか」を考えるのも大事なんだなと実感しました。

結論。

AIが生成したコード、ちゃんと読むと勉強になる笑