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

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

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

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

Q&A

解決済

4回答

2805閲覧

連想配列の重複している要素をカウントする

ovyzppfxbebqaek

総合スコア12

JavaScript

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

0グッド

1クリップ

投稿2021/09/30 09:30

編集2021/09/30 09:59

目標

以下のような文字列が入っている連想配列のうち、重複している日付の数をカウントしたいのですが、やり方が思いつきません。

javascript

1const dateList = [ 2 { createdAt: '2021-09-30' }, 3 { createdAt: '2021-09-29' }, 4 { createdAt: '2021-09-29' }, 5 { createdAt: '2021-09-28' }, 6 { createdAt: '2021-09-28' }, 7 { createdAt: '2021-09-28' }, 8 { createdAt: '2021-09-27' }, 9]

上のdateListには日付の重複があります。2021-09-30は1回、2021-09-29は2回、2021-09-28は3回、2021-09-27は1回と。
この重複している回数を取得し、以下のように求めたいです。外部ライブラリは使用しても構いません。
実現したい連想配列:

javascript

1const newDateList = [ 2 { createdAt: '2021-09-30', count: 1}, 3 { createdAt: '2021-09-29', count: 2}, 4 { createdAt: '2021-09-28', count: 3}, 5 { createdAt: '2021-09-27', count: 1}, 6]

考えたこと

reduceが使えないか考えました。しかし、カウント数の扱い方がよくわかりません。これでは各文字列に対応するcountが求まりません。
この場合reduceは適切ではないのでしょうか。

javascript

1const reducer = (previousValue, currentValue, currentIndex, array) => { 2 let count = 1; 3 if(previousValue == currentValue) { 4 count += 1; 5 } 6} 7const newDateList = dateList.reduce(reducer, initialValue);

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

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

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

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

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

m.ts10806

2021/09/30 09:43

まず、自身で思うように(もしくはできるやり方で)やってみては。 この質問内容では、質問というより作業依頼です。
guest

回答4

0

javascript

1 2const dateList = [ 3 { createdAt: '2021-09-30' }, 4 { createdAt: '2021-09-29' }, 5 { createdAt: '2021-09-29' }, 6 { createdAt: '2021-09-28' }, 7 { createdAt: '2021-09-28' }, 8 { createdAt: '2021-09-28' }, 9 { createdAt: '2021-09-27' }, 10] 11 12const convertDateList = (dateList) => { 13 let noDuplicateList = []; 14 const newDateList = dateList.reduce((acc, obj) => { 15 obj.count = 1; 16 let key = obj['createdAt'] 17 if (noDuplicateList.includes(key)) { 18 let current_count = acc.slice(-1)[0].count 19 index = acc.findIndex((v) => v.createdAt === key && v.count === current_count) 20 acc[index].count += 1 21 } else { 22 acc.push(obj) 23 noDuplicateList.push(key) 24 } 25 return acc 26 }, []); 27 return newDateList 28} 29

一応、自力でも解決できたので参考として載せておきます。
内容は以下の通りです。

  1. reduce()dateListを走査。
  2. createdAtnoDuplicateListに含まれているかチェック。
  3. 含まれている場合、count += 1
  4. 含まれているいない場合、noDuplicateList追加、countはそのまま。

投稿2021/10/01 08:26

編集2021/10/01 14:38
ovyzppfxbebqaek

総合スコア12

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

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

退会済みユーザー

退会済みユーザー

2021/10/01 09:41

自己解決のコード掲載、ありがとうございます。 ベストアンサーにお選び頂いてツッコミ入れるのも野暮な話かもしれませんが、こちらのコードに対して、2点あります。 (1) これは単純なタイプミスだと思いますが、こちらのコードの以下の行 const newDateList => (dateList) { は文法エラーになりますので、以下が正しいでしょうか? const newDateList = (dateList) => { (2) 上記の(1) で const newDateList = (dateList) => { が正しいとすると、newDateList を関数として作られたということだと思いますが、たとえば const result = newDateList(dateList); とすると、newDateList()関数は、引数として与えるdateListの要素自体にcountプロパティを追加しているので、newDateList(dateList) によるカウント作業が終わったあと、dateList の各要素は以下のようになっています。 [ { createdAt: '2021-09-30', count: 1 }, { createdAt: '2021-09-29', count: 2 }, { createdAt: '2021-09-29', count: 1 }, { createdAt: '2021-09-28', count: 3 }, { createdAt: '2021-09-28', count: 1 }, { createdAt: '2021-09-28', count: 1 }, { createdAt: '2021-09-27', count: 1 } ] ですが、カウント集計によって、元の配列の各要素は変更されないのが望ましいのでは?と思ったりもしています。       以上の2点です。
ovyzppfxbebqaek

2021/10/01 14:40

コメントありがとうございます。 おっしゃる通り、(1),(2)ともに間違いでした。 修正しておきました。
guest

0

javascript

1const newDateList = [...new Set(dateList.map(x=>x.createdAt))].map(x=>({createdAt:x,count:dateList.filter(y=>y.createdAt==x).length})); 2console.log(newDateList);

投稿2021/10/01 01:46

yambejp

総合スコア115012

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

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

0

ベストアンサー

なるほどのう。reduce でやったろゆうんは、間違ってないと思うわ。

で、reduce でやるんやったら、まずエラーになるの承知で

javascript

1const newDateList = dateList.reduce();

とひとまず書いてしまう。
これはreduceに渡すべき関数を渡してないんやから
Uncaught TypeError: undefined is not a function
ゆうエラーになりますわ。

ほんで次にやることは、reduce()の

  • 第1引数にはとりま空関数 () => {} 渡しとく。これで上のエラーは消える。
  • 第2引数には、newDateListとして得たいのは配列なので、その初期値として空配列[]を渡しとく。

するとこない

javascript

1const newDateList = dateList.reduce(() => {}, []);

になるねんな。そうすると、エラーは消えて、newDateList には undefined が入ってくる。

ほんで次は、reduceの第1引数に渡している関数() => {} に引数とreturnを加えるとこ考えるねん。

  • 第1引数は、reduceの第二引数に渡している初期値と同じ型のものが入ってくるので、今の場合配列や。そやから、aryとする。
  • 第2引数は、reduceのレシーバーであるdateListの要素のオブジェクトなので e とか obj にしてもよいが、今回の場合、createdAtプロパティしか使わないので、ナウなヤングは分割代入 { created } 使っとこ。
  • そして、return するのは、第一引数と同じ型のものなので、とりま第一引数と同じ ary を返しておく。

ゆうことで、こない

javascript

1const newDateList = dateList.reduce((ary, { createdAt }) => { 2    // TODO: ここを埋める 3 return ary; 4}, []);

になって、ここまでで、newDateList には空配列が入ってくる。reduceでやると決めたら、ここまでを、まずはテンプレとしてガーッと書いてしまってやな、ほんで次に// TODO: ここを埋める んとこ、どうするか考えるとええよ。

今回の場合、とりまこないな感じになるかのう。

javascript

1const newDateList = dateList.reduce((ary, { createdAt }) => { 2 const matchedObj = ary.find(obj => obj.createdAt === createdAt); 3 if (matchedObj) 4 matchedObj.count ++; 5 else 6 ary.push({ createdAt, count: 1 }); 7 return ary; 8}, []);

サンプル

これでひとまず要件を満たすものができる。ここから工夫するとすれば、

  • 毎回、find で ary の先頭から createdAt が一致するカウンターオブジェクトを探さないで済むようにする

っていう改良の余地があってやな、たとえばMapを使ってこんなんなるで。

javascript

1const [newDateList] = dateList.reduce(([ary, map], { createdAt }) => { 2 const matchedObj = map.get(createdAt); 3 if (matchedObj) 4 matchedObj.count ++; 5 else { 6 const newObj = { createdAt, count: 1 }; 7 ary.push(newObj); 8 map.set(createdAt, newObj); 9 } 10 return [ary, map]; 11}, [[], new Map]);

サンプル

以上ですぅ〜

補足: lodash使うで

質問に

外部ライブラリは使用しても構いません。

ってありよったから、ワテが何かと世話になっとるlodash先生使うやつも書いとくわ。

javascript

1const newDateList = 2 _(dateList) 3 .groupBy('createdAt') 4 .mapValues('length') 5 .toPairs() 6 .map(([createdAt, count]) => ({ createdAt, count })) 7 .value();

サンプル

投稿2021/09/30 13:43

編集2021/09/30 15:05
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

日付をキーにして集計するのはどうでしょうか。

javascript

1const dateList = [ 2 { createdAt: '2021-09-30' }, 3 { createdAt: '2021-09-29' }, 4 { createdAt: '2021-09-29' }, 5 { createdAt: '2021-09-28' }, 6 { createdAt: '2021-09-28' }, 7 { createdAt: '2021-09-28' }, 8 { createdAt: '2021-09-27' }, 9] 10 11let wk = {} 12for (let x of dateList) { 13 if (!(x['createdAt'] in wk)) wk[x['createdAt']] = 0 14 wk[x['createdAt']] += 1; 15} 16 17let newDateList = [] 18for (let k in wk) { 19 newDateList.push({createdAt:k,count:wk[k]}) 20} 21 22console.log(newDateList)

投稿2021/09/30 11:12

takasima20

総合スコア7460

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問