質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

404閲覧

日付毎に日付の要素が何件あるかカウントしたい

anzi1230

総合スコア19

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

2クリップ

投稿2022/08/24 16:21

編集2022/08/24 16:43

実現したいこと

日付毎に日付の要素が何件あるかカウントしたいです
(membersのday要素をカウントしたい)
期待値:
2022-07-23→2
2022-07-24→2
2022-07-25→1
2022-07-23→2

該当のソースコード

const members = [ { name: "foo", score: 10, day: '2022-07-23' }, { name: "bar", score: 20, day: '2022-07-23' }, { name: "bar", score: 20, day: '2022-07-24' }, { name: "bar", score: 20, day: '2022-07-24' }, { name: "bar", score: 20, day: '2022-07-25' }, { name: "bar", score: 20, day: '2022-07-26' }, { name: "baz", score: 30, day: '2022-07-26' }, ]

試したこと

const groupBy = members.reduce((result, current) => { let counts = 0 const element = result.find(value => value.day === current.day); console.log(element) if (element) { counts++; } else { counts = 1 } return result; }, 0); console.log(groupBy);

補足情報(FW/ツールのバージョンなど)

同じ日付の時はcountsを++して
それ以外はcounts=1にしてみましたが
エラーになり出力されませんでした。

resultを初めて使ったのですが、やり方があっているのか分かりません
どなたかご教授いただければ幸いです

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

reduce使うのなら、例えばこうとか:

javascript

1const members = [ 2 { name: "foo", score: 10, day: '2022-07-23' }, 3 { name: "bar", score: 20, day: '2022-07-23' }, 4 { name: "bar", score: 20, day: '2022-07-24' }, 5 { name: "bar", score: 20, day: '2022-07-24' }, 6 { name: "bar", score: 20, day: '2022-07-25' }, 7 { name: "bar", score: 20, day: '2022-07-26' }, 8 { name: "baz", score: 30, day: '2022-07-26' }, 9]; 10 11 12const groupBy = members.reduce((result, { day }) => ({ 13 ...result, [day]: (result[day] || 0) + 1 14}), {}); 15 16console.log(groupBy);

{ '2022-07-23': 2, '2022-07-24': 2, '2022-07-25': 1, '2022-07-26': 2 }

補足

lodash 使ってよければ、 groupBy というメソッドがあるのでそれ使ってこう:

javascript

1const groupBy = _(members).groupBy('day').mapValues('length').value();

👉 https://codepen.io/su507/pen/ExEJrgy?editors=0012

補足2

質問にあるコードの趣旨を活かして修正した案を挙げておきます。

javascript

1const groupBy = members.reduce((result, current) => { 2 if (result[current.day] > 0) { 3 result[current.day] ++; 4 } else { 5 result[current.day] = 1; 6 } 7 return result; 8}, {});

一番重要な修正点は、 reduce の第二引数に与える初期値を 0 から 空オブジェクト {} に修正していることです。

最終的に欲しいのは日付ごとの件数ですから、単一の数字ではないはずです。reduceを使うときの考えどころは以下の2つあります。

(1) 第二引数にどのような初期値を与えるか?(単一の数字 0 でよいのか? 空の文字列""や空の配列[]がよいのか?空のオブジェクト{}か? Set か Map か?あるいはこれらの複合か?)

(2) その初期値をaccumulator として望む結果を得るには、第一引数の関数をどう書けばよいか?

(1)の初期値を目的に適うような正しいものを選ぶことができれば、それをもとに(2)でロジックを実装すればよいことになりますが、そもそも(1)を間違うといくら (2)で試行錯誤しても袋小路に入ってしまいます。

また(1) にいくつかの選択肢がありどれも同じように目的を果たせるが、(2) のコードをより完結にあるいは効率のよいものに書ける、よい良い初期値というものも(まま)あり得ます。

なので、(2)を徒労にしないためにはまずは(1)で間違わないというのが大事です。

投稿2022/08/24 18:33

編集2022/08/25 11:59
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

anzi1230

2022/08/25 04:28

ありがとうございます! reduceの例えが私には、難易度高すぎて、ちょっと理解できていません。。 [day]: (result[day] || 0) + 1 これは何をやっている所なのでしょうか? lodashはとても便利ですね!勉強になりましたありがとうございます!
退会済みユーザー

退会済みユーザー

2022/08/25 11:33

> [day]: (result[day] || 0) + 1 > これは何をやっている所なのでしょうか? 配列members の各要素が、reduce に渡している関数の第二引数に入ってきます。 それを { day } という分割代入によって、各要素のday プロパティだけを取得します。 reduce に渡している関数は、第一引数で渡される result に対してday の値に応じて、以下のいずれかを行う選択肢があります。 (1) result オブジェクト自体の day にあたるカウント数を1増やして、result を返す。 (2) result オブジェクトの内容をコピーし、day にあたる数だけ1増やした新しいオブジェクトを作って、それを返す。 回答のコードでは (2) のほうを実装しています。 なぜ(2)を選んだか?といえば、(2)だとreduce に渡している関数を詰めて書けば、return 文を書かなくて済むように書けるのですが、 (1)では return文を書かなくて済むまでコードを詰めるのが難しいからです。 回答したコードでは、reduce に渡している関数の返すオブジェクトは { ...result, [day]: (result[day] || 0) + 1 } というものですが、...result で現resultの内容を展開して、その後ろの [day]: (result[day] || 0) + 1 によって、当該日付のカウント数が - すでにあればそれを1増やした数で上書きし、 - 無ければ 1 を設定します。 (result[day] || 0) + 1 と書かないで単に result[day] + 1 としてしまうと、result の初期値は空オブジェクトなので、当該日付が何であっても result[day] は undefined になり、undefined に 1 を足すことになり、 undefined に 1 を足したときに、undefinedを0に暗黙に評価してくれればよいのですが、 そうはならず undefined + 1 は NaN になり、以後、NaN にどんな数を足してもNaNのまま なので望む結果が得られません。 これを回避するために (result[day] || 0) + 1 とすることで、result[day] が undefined の場合は、(result[day] || 0) の部分は || の後ろの 0 になり、 0 +1 という足し算が行われて、1 になるという仕組みです。
退会済みユーザー

退会済みユーザー

2022/08/25 12:00

上記コメントの > (1) result オブジェクト自体の day にあたるカウント数を1増やして、result を返す。 の例として、質問にあるコードの修正したものを回答に追記しました。
anzi1230

2022/08/25 16:33

とてもご丁寧に解説頂き、本当にありがとうございました! 教えていただいた内容は「理解できた気になっています!」 一旦手を動かして再度解説を読み直して理解できるまでやってみたいと思います (result[day] || 0) + 1←これは他のサイトでもこんな使い方していて、分からなかったので 仕組みが分かり大変すっきりしています(笑) まずは手を動かしてみます! 本当にありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問