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

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

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

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

Q&A

解決済

3回答

667閲覧

配列内の数字を項目を分けて足したい

jsrookie

総合スコア24

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

JavaScript

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

0グッド

0クリップ

投稿2019/08/07 18:37

発生している問題、目指している形

初心者なためかなり冗長なコードになっていると思いますがご了承ください。
ソースコードの様なtxtを読み込むと以下の様な配列になるプログラムを作ったのですが、各配列内でx,yを分けて数字を足したいです。
result5[a]=[[x, 1000, a], [y, 1000, a], [y, 1, a], [x, 1000, a]]
result5[b]=[[x, 100, b], [x, 10, b], [x, 100, b]]
result5[c]=[[y, 100, c], [y, 10, c], [x, 1, c]]
result5[d]=[[x, 1, d], [x, 10, d]]

最終的には配列内のa,b,c,dは消し、以下の様な形にしたいです。
result5[a]=[[x, 2000], [y, 1001]]
result5[b]=[x, 210]
result5[c]=[[x, 1], [y, 110]]
result5[d]=[x, 11]

result5[k]のkの値が同じ時に何度も数字を足してしまったり、xとyを分けて数字を足すことができませんでした。
どうかご教授お願いします。

該当のソースコード

JavaScript

1<body> 2<form name="test"> 3<input type="file" id="selfile"><br> 4<textarea name="txt" rows="10" cols="60" readonly></textarea> 5</form> 6 7<script> 8 9var obj1 = document.getElementById("selfile"); 10 11obj1.addEventListener("change",function(evt){ 12 13 var file = evt.target.files; 14 var reader = new FileReader(); 15 reader.readAsText(file[0]); 16 17 reader.onload = function(ev){ 18 19 //テキストエリアに表示 20 document.test.txt.value = reader.result.toLowerCase(); 21 var result2=reader.result.toLowerCase().split("\n"); 22 23 var result3=[]; 24 for (var i = 0; i <result2.length; i++) { 25 result3.push(result2[i].split(/\s+/)); 26 } 27 28 for (var i = 0; i<result3.length; i++) { 29 if(result3[i].length>=6){ 30 while (result3[i].length>=6){ 31 result3[i].pop(); 32 } 33 } 34 } 35 36 Array.prototype.divide = function(n){ 37 var ary = this; 38 var idx = 0; 39 var results = []; 40 var length = ary.length; 41 42 while (idx + n < length){ 43 var result = ary.slice(idx,idx+n) 44 results.push(result); 45 idx = idx + n 46 } 47 var rest = ary.slice(idx,length+1) 48 results.push(rest) 49 return results; 50 } 51 52 result4=[]; 53 for (var i = 0; i<result3.length; i++) { 54 result4.push(result3[i].divide(1)); 55 } 56 57 for (var i = 0; i<result4.length; i++) { 58 if(result4[i][4][0].indexOf("x") >= 0){ 59 result4[i][0].unshift(1000); 60 result4[i][0].unshift("x"); 61 result4[i][1].unshift(100); 62 result4[i][1].unshift("x"); 63 result4[i][2].unshift(10); 64 result4[i][2].unshift("x"); 65 result4[i][3].unshift(1); 66 result4[i][3].unshift("x"); 67 } else if (result4[i][4][0].indexOf("y") >= 0){ 68 result4[i][0].unshift(1000); 69 result4[i][0].unshift("y"); 70 result4[i][1].unshift(100); 71 result4[i][1].unshift("y"); 72 result4[i][2].unshift(10); 73 result4[i][2].unshift("y"); 74 result4[i][3].unshift(1); 75 result4[i][3].unshift("y"); 76 } 77 } 78console.log(result4); 79 80var result5 = []; 81for (var i = 0; i < result4.length; i++) { 82 for (var j = 0; j < result4[i].length; j++) { 83 k = result4[i][j][2]; 84 if (!result5[k]) { 85 result5[k] = []; 86 } 87 result5[k].push(result4[i][j]); 88 } 89} 90console.log(result5); 91 } 92},false); 93</script> 94</body>

txt

1a b b d X 2a c c a Y 3a b d c X

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

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

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

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

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

guest

回答3

0

スマートではないですが、下記で実現できました。

javascript

1var result5 = new Map( 2 [ 3 ['a', [['x', 1000, 'a'], ['y', 1000, 'a'], ['y', 1, 'a'], ['x', 1000, 'a']]], 4 ['b', [['x', 100, 'b'], ['x', 10, 'b'], ['x', 100, 'b']]], 5 ['c', [['y', 100, 'c'], ['y', 10, 'c'], ['x', 1, 'c']]], 6 ['d', [['x', 1, 'd'], ['x', 10, 'd']]] 7 ] 8); 9 10var result = new Map(); 11for (const [key, value] of result5.entries()) { 12 const o = new Map(); 13 for(let l of value) { 14 const v = o.get(l[0]) || 0 15 o.set(l[0], l[1] + v); 16 } 17 const r = []; 18 for( const [k, v] of o.entries()){ 19 r.push([k, v]) 20 } 21 result.set(key, r); 22} 23console.log(result);

xとyはキーとなるので、配列ではなくMapを使用した方が良いかと思います。

投稿2019/08/08 02:09

yamap55

総合スコア1376

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

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

jsrookie

2019/08/09 23:03

回答ありがとうございます! yamap_55さんのプログラムで動作確認できました。 しかし、私の考えるresult5と形が違ったためか私のプログラム上だと上手くいきませんでした。 result5の形を変えたりすることで私のプログラムでも動くようにしたいと思います。 配列のMapはまだあまり扱ったことがないため勉強頑張ります。 ありがとうございました。
guest

0

ベストアンサー

こんにちは

ご質問を拝読しまして、 result5 は以下のようなオブジェクトであると把握しました。

javascript

1{ 2 a: [['x', 1000, 'a'], ['y', 1000, 'a'], ['y', 1, 'a'], ['x', 1000, 'a']], 3 b: [['x', 100, 'b'], ['x', 10, 'b'], ['x', 100, 'b']], 4 c: [['y', 100, 'c'], ['y', 10, 'c'], ['x', 1, 'c']], 5 d: [['x', 1, 'd'], ['x', 10, 'd']] 6}

この回答では、上記のオブジェクト result5 に含まれる配列に対して集計処理を行って、ご質問にある

最終的には配列内のa,b,c,dは消し、以下の様な形

の内容を持つオブジェクトを、 result6 という変数に得るためのコードを示します。

まず、以下のような関数summarize(ary) を作成します。

javascript

1const summarize = (ary) => { 2 const map = ary.reduce((m, e) => m.set(e[0], (m.get(e[0]) || 0) + e[1]), new Map()); 3 return [...map].sort( (e1,e2) => e1[0].localeCompare(e2[0])); 4}

上記の関数summarize(ary)は、引数 ary にたとえば

javascript

1[['x', 1000, 'a'], ['y', 1000, 'a'], ['y', 1, 'a'], ['x', 1000, 'a']]

が与えられると、ご質問の要件に沿って、各要素の配列の先頭の文字ごとに、2番目の要素である数値を足し上げた配列

javascript

1[['x', 2000], ['y', 1001]]

を返します。また、引数 ary

javascript

1[['y', 100, 'c'], ['y', 10, 'c'], ['x', 1, 'c']]

が与えられた場合は、足し上げたうえで、 先頭要素のアルファベット順に並び替えて、

javascript

1[['x', 1], ['y', 110]]

を返します。

上記の summarize(ary)を使うと、冒頭に書いた result5 から result6 を得るには、以下のようにすればよいです。

javascript

1const result6 = Object.entries(result5).reduce((obj, [k,v]) => ({...obj, [k]: summarize(v)}), {});

上記により、result6 には各配列が集計されているオブジェクトが入ります。

以下は、上記を動作確認するために jsFiddle に上げたものです。

以上、参考になれば幸いです。

追記1

補足ですが、上記に挙げたコードの中で、 result5 から result6 を得る以下の行

javascript

1const result6 = Object.entries(result5).reduce((obj, [k,v]) => ({...obj, [k]: summarize(v)}), {});

については、lodash の _.mapValues を使うと、以下のように少し短く書けます。

javascript

1const result6 = _.mapValues(result5, summarize);

lodash はオブジェクトや配列の操作で便利なメソッドを提供しており、用途にうまく合ったメソッドがみつかると、コードを短くできることがあります。

追記2

result5 からの合計処理だけではなく、ご質問に挙げられているソースコード全体について、リファクタ案を書いてみましたので、参考までに提示します。作成したコードは以下に上げています。

最終的な修正後のJavascriptのコードは以下です。

以下、各コミットを順を追って説明します。

  • initial commit では、ご質問に挙げられているコードをそのままコピペしたうえで、HTML と JavaScript のファイルを分けました。

 

 

 

  • 以下は、 result3 から result4 を作る処理を3段階でリファクタしました。

 (1) result4 の作成部分を修正(その1): 元のコードにある、 divide はかなり力作という感じで恐縮ですが、 .divide(1) と、要素が1個の配列に区切るならば、修正後のように短く書けます。
(2) result4 の作成部分を修正(その2) : result4 を作る2段階目です。map を二重にして、unshift を使わずに長さが 3 の配列を作ります。

 

  • result5 の作成にreduceとfilterを使用 :result4 から result5 を作る処理を reduce と filter を使ってみました。元のコードでは、result5 は配列ですが、 a, b などがキーになるのでオブジェクトが得られるようにしています。

 

  • 以下の2つは、先の回答に書いたコードを追加したものです。

 (1) result6 の作成を追加
(2) lodash の利用

配列のメソッド、mapreduce, filterスプレッド構文は、配列やオブジェクトを処理するプログラムを書くときに、いろいろな場面で重宝します。

投稿2019/08/08 03:47

編集2019/08/09 15:28
jun68ykt

総合スコア9058

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

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

jsrookie

2019/08/09 23:03

前回の質問に引き続き回答ありがとうございます! まさに求めていた結果が得られて感謝しかないです。 プログラムがどう動いているのか説明して下さったのでとても分かりやすかったです。 本当にありがとうございました。
jsrookie

2019/08/09 23:36

また、コード全体の修正までしていただいてありがとうございます。 独学なため誰かに修正していただく機会は皆無だったためとても勉強になりました。 私の冗長なコードがこんなに短くなるとは驚きです。 本当にありがとうございました。 因みにdivideは自作ではなく、調べたら要素4つ毎に区切るコードが出てきたのでそれを1個で区切るよう変えたものです。
jun68ykt

2019/08/10 12:42 編集

どういたしまして。 > 独学なため誰かに修正していただく機会は皆無だったためとても勉強になりました。 ありがとうございます。そう仰って頂けますと回答者冥利に尽きます。 > 因みにdivideは自作ではなく、調べたら要素4つ毎に区切るコードが出てきたのでそれを1個で区切るよう変えたものです。 なるほどですね。 そのように、すでに誰かが作ってくれたコードを、自分が書こうとしているコードに利用できるか見極めて、必要ならちょっと手を加えて、利用させてもらう(または、検証した結果、利用しないという判断をする。)ということも、何かひとまとまりのものを作ろうというときに、とても大事になってきます。 jsrookieさんはJQuery のご質問もあるようですが、JQuery だったりReactだったりのライブラリを使ったフロントエンド開発をやろうとするときに、こういったライブラリの使い方というのは、公式ドキュメントのサンプルを写経すれば、だいたいお決まりの書き方が分かってきますが、どのライブラリを使うにせよ、自分の作ろうとしているWEBアプリなりシステムの対象領域("ドメイン"といったりします。)における、個別具体的な問題解決をするコードというのは、配列やオブジェクトの操作や値の置き換え、条件に合致する要素の検索あるいは除外といったコードを、(ライブラリの使い方とは違って)お手本がない中で書くことになります。 今回のご質問でいえば、 与えられたテキストファイルから、['x', 1000, 'a'] といった、 'X' と 10のN乗 と 'a' という3つの組を作る。そしてそれらを集計する。 というのが個別具体的な問題です。 そのときに、少ないコード量で大きな仕事(または、いい仕事)をしてくれるコードを思いついて実際に書くには、配列操作でいうと、 map, reduce, filter、find といったような、関数を引数に取る関数("高階関数" といいます。)を使ったコードがスラスラ出てくるか、というのが、初心者からワンステップ上に登るポイントのひとつと思います。 以下にまとまった記事をご紹介します。 Qiita: JavaScript 高階関数を説明するよ-代表的な高階関数(may88seijiさん) https://bit.ly/2TkMecE for 文を使ったほうが明らかに分かり易いコードになる場合は別として、今後しばらくは、 配列に対して for ループのコードを書こうとしたときに、いったん手を留めて、 「これを map やforEach, reduce などで書けないか? 」 と、ご自身に制約を課してみるのも面白いかもしれません。 それと、これは今すぐ始めなくてもいいですが、for ループを書く前に map などの高階関数を使ったコードが出てくるようになるために、今後のどこかで以下も取り組むとよいかもしれません。 ・ Lisp にちょっと入門してみる。 ・ JavaScript による関数型プログラミングを勉強してみる。具体的には   https://amzn.to/2OLg2jU  といったような本を読む。 また上記のような、javascript によるプログラミング力を高めるときに、基礎の点検というのが外せない学習アイテムになってきますが、そのときに以下の本をおすすめします。(もう読んでいたらすみません) ・開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質  https://amzn.to/2H0Rtcr  手前味噌ですが、上記の本のサンプルコード集を以下にリストしています。  https://bit.ly/31x7pLr 今後の学習が捗ることをお祈り申し上げます。
guest

0

こういうことでしょうか?

js

1var result5={}; 2result5['a']=[['x', 1000, 'a'], ['y', 1000, 'a'], ['y', 1, 'a'], ['x', 1000, 'a']]; 3result5['b']=[['x', 100, 'b'], ['x', 10, 'b'], ['x', 100, 'b']]; 4result5['c']=[['y', 100, 'c'], ['y', 10, 'c'], ['x', 1, 'c']]; 5result5['d']=[['x', 1, 'd'], ['x', 10, 'd']]; 6 7Object.keys(result5).map(function(row){ 8 var obj = result5[row].reduce(function(obj, arr){ 9 if ( ! (arr[0] in obj) ) obj[arr[0]] = 0; 10 obj[arr[0]] += arr[1]; 11 return obj; 12 },{}); 13 return Object.keys(obj).map(function(e){ 14 return [e, obj[e]] 15 }) 16}).map(function(e){ 17 if (e.length == 1) return e[0]; 18 return e; 19}); 20 21 22 23/* 24[ 25 [ 26 [ 27 "x", 28 2000 29 ], 30 [ 31 "y", 32 1001 33 ] 34 ], 35 [ 36 "x", 37 210 38 ], 39 [ 40 [ 41 "y", 42 110 43 ], 44 [ 45 "x", 46 1 47 ] 48 ], 49 [ 50 "x", 51 11 52 ] 53] 54*/

投稿2019/08/08 02:34

Lhankor_Mhy

総合スコア35860

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

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

jsrookie

2019/08/09 23:07

回答ありがとうございます! まさに私の求めていたものです。 初心者の私でも理解しやすそうで、こんな方法があるのかと勉強になりました。 本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問