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

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

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

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

JavaScript

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

Q&A

解決済

3回答

1577閲覧

多重配列の重複した部分を分類したい

jsrookie

総合スコア24

HTML5

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

JavaScript

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

0グッド

0クリップ

投稿2019/08/01 18:59

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

ソースコード(js)はテキストを読み込み、細かく分けて配列にしているものです。

例えばソースコード(txt)を読み込み
result4=[
[ [a,1], [b,2], [c,x], [d,y] ],
[ [a,y], [b,x], [c,2], [d,1] ]
]
の様な多重配列があるとき、一番小さい配列の2番目の文字や数字(この場合は1,2,x,y)が同じものを分類したいです。
つまり、result4[0][0]の[a,1]とresult4[1][3]の[d,1]、同様に[c,x]と[b,x]のような配列をすべて分類したいです。

調べたところ1重の配列の分類方法は出てきたのですが、多重ではどうすればよいか分かりませんでした。
ご教授お願いします。

該当のソースコード

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 29 for (var i = 0; i<result3.length; i++) { 30 if(result3[i].length>=5){ 31 while (result3[i].length>=5){ 32 result3[i].pop(); 33 } 34 } 35 } 36 37 Array.prototype.divide = function(n){ 38 var ary = this; 39 var idx = 0; 40 var results = []; 41 var length = ary.length; 42 43 while (idx + n < length){ 44 var result = ary.slice(idx,idx+n) 45 results.push(result); 46 idx = idx + n 47 } 48 var rest = ary.slice(idx,length+1) 49 results.push(rest) 50 return results; 51 } 52 53 result4=[]; 54 for (var i = 0; i<result3.length; i++) { 55 result4.push(result3[i].divide(1)); 56 } 57 58 for (var i = 0; i<result4.length; i++) { 59 result4[i][0].unshift("a"); 60 result4[i][1].unshift("b"); 61 result4[i][2].unshift("c"); 62 result4[i][3].unshift("d"); 63 } 64console.log(result4); 65 } 66},false); 67</script> 68</body>

txt

11 2 x y 2y x 2 1

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

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

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

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

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

think49

2019/08/01 23:13

「分類」とは、どういう結果ですか。 「1重の配列の分類方法」のURLを開示できますか。
think49

2019/08/02 03:29

> duplicate_check.jsのc 「非重複な要素を削除する」ということですか。質問文の要件を修正して下さい。
guest

回答3

0

ベストアンサー

こんにちは

多重ではどうすればよいか分かりませんでした。

とのことですが、

多重

とは、具体的にはどのような階層構造の中に目的の配列があるのかについて、ご質問からは読み取れませんでしたので、全体の配列の中のどこにあっても、長さが2で要素が文字列か数字であるような

一番小さい配列

を拾い出すコードを回答します。なお、以下では、この

一番小さい配列

のことを minimal な配列 と呼び、 minimal な配列の先頭要素を head, 2番目の要素を tail と呼ぶことにして、これらを変数名やプロパティ名、関数名に使っています。

index.html

html

1<!DOCTYPE html> 2<html lang="ja"> 3<head> 4 <meta charset="UTF-8"> 5 <title>Q203923</title> 6 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script> 7 <script src="./assort.js"></script> 8 <script> 9 function main() { 10 var obj1 = document.getElementById("selfile"); 11 12 obj1.addEventListener("change",function(evt) { 13 14 var file = evt.target.files; 15 var reader = new FileReader(); 16 reader.readAsText(file[0]); 17 18 reader.onload = function (ev) { 19 var text = reader.result.toLowerCase(); 20 document.test.txt.value = text; 21 22 var result = assort(text); 23 24 console.log(result); 25 } 26 }); 27 } 28 29 document.addEventListener('DOMContentLoaded', main); 30 </script> 31</head> 32<body> 33<form name="test"> 34 <input type="file" id="selfile"><br> 35 <textarea name="txt" rows="10" cols="60" readonly></textarea> 36</form> 37</body> 38</html>

上記で、選ばれたファイルの内容を受け取って、結果を返す assort という関数を作りました。関数 assort は、以下のファイル assort.js の最後にあります。minimal な配列を収集した後、重複を除くための処理に、 lodash の uniqBy を使っています。

assort.js

javascript

1const isMinimal = a => ( 2 Array.isArray(a) && 3 a.length === 2 && 4 [typeof a[0], typeof a[1]].every( 5 t => ['number', 'string'].includes(t) 6 ) 7); 8 9const getMinimals = (a, result=[]) => { 10 if (isMinimal(a)) 11 result.push(a); 12 else if (Array.isArray(a)) 13 a.forEach(e => { getMinimals(e, result); }) 14 15 return result; 16} 17 18const compare = (e1, e2) => { 19 const type1 = typeof e1; 20 const type2 = typeof e2; 21 22 if (type1 !== type2) { 23 return type1 === 'number' ? -1 : 1 24 } else { 25 return type1 === 'number' ? e1 - e2 : e1.localeCompare(e2) 26 } 27}; 28 29const getKeys = ary => 30 ['heads', 'tails'].reduce((m, k, i) => 31 m.set(k, _.uniq(ary.map(e => e[i])).sort(compare)) 32 , new Map()); 33 34const assortByKeys = (keys, ary) => { 35 const heads = keys.get('heads').map(k => ({ 36 value: k, 37 minimalArrays: ary.filter(e => e[0] === k) 38 })); 39 40 const tails = keys.get('tails').map(k => ({ 41 value: k, 42 minimalArrays: ary.filter(e => e[1] === k) 43 })); 44 45 return { heads, tails } 46} 47 48const assort = text => { 49 50 // 先頭の '変数名=' を除去 51 text = text.replace(/^(.+)=/, '') 52 53 // 配列要素として出現する変数名をダブルコーテーションで囲む。 54 const jsonStr = text.replace(/([a-z][a-z0-9]*)/g, name => `"${name}"`); 55 56 // JSON文字列としてパース 57 const data = JSON.parse(jsonStr); 58 59 // 最小配列(要素の数が2個で、要素が数または文字列の配列) を収集 60 const minimals = _.uniqBy(getMinimals(data), e => e.join(',')) 61 62 // 分類キーを作成 63 const keys = getKeys(minimals) 64 65 // 最小配列を分類する 66 const result = assortByKeys(keys, minimals) 67 68 return result; 69} 70

上記によって、以下のテキストファイル

input.txt

text

1result4=[ 2[ [d,1], [b,2], [c,x], [d,y] ], 3[ [a,y], [b,x], [c,2], [d,1] ] 4]

を読むと、result には以下のようなオブジェクトが入ります。

javascript

1{ 2 heads: [ 3 { value: "a", minimalArrays: [["a","y"]]}, 4 { value: "b", minimalArrays: [["b",2],["b","x"]]}, 5 { value: "c", minimalArrays: [["c","x"],["c",2]]}, 6 { value: "d", minimalArrays: [["d",1],["d","y"]]} 7 ], 8 tails: [ 9 { value: 1, minimalArrays: [["d",1]]}, 10 { value: 2, minimalArrays: [["b",2],["c",2]]}, 11 { value: "x", minimalArrays: [["c","x"],["b","x"]]}, 12 { value: "y", minimalArrays: [["d","y"],["a","y"]]} 13 ] 14}

また、以下のような入力

input2.txt

text

1result5=[ 2 3 [ 4 [a,1],[b,5],[ [d,8], [c,3], [a,7], [c,5] ] 5 ], 6 7 [ 8 [[ [d,8], [a,1] ], [c, 6], [[[ [x,y], [x,z], [x,5] ]]] ], 9 [f,6], [ [d, 7], [c, 5] ] 10 ] 11 12]

に対しても、以下が得られます。

javascript

1{ 2 heads: [ 3 { value: "a", minimalArrays: [["a",1],["a",7]]}, 4 { value: "b", minimalArrays: [["b",5]]}, 5 { value: "c", minimalArrays: [["c",3],["c",5],["c",6]]}, 6 { value: "d", minimalArrays: [["d",8],["d",7]]}, 7 { value: "f", minimalArrays: [["f",6]]}, 8 { value: "x", minimalArrays: [["x","y"],["x","z"],["x",5]]} 9 ], 10 tails:[ 11 { value: 1, minimalArrays: [["a",1]]}, 12 { value: 3, minimalArrays: [["c",3]]}, 13 { value: 5, minimalArrays: [["b",5],["c",5],["x",5]]}, 14 { value: 6, minimalArrays: [["c",6],["f",6]]}, 15 { value: 7, minimalArrays: [["a",7],["d",7]]}, 16 { value: 8, minimalArrays: [["d",8]]}, 17 { value: "y", minimalArrays: [["x","y"]]}, 18 { value: "z", minimalArrays: [["x","z"]]} 19 ] 20}

上記の回答に書いたコードでは、

  • getMinimals が再帰関数になっているので、想定していない入力があると無限ループになる恐れがありますので、実用化するには何らかの対策が必要

  • 一度、すべての minimal な配列を拾い出してから分類しているので、やや冗長なコードになっています。

といった課題が残りますが、各論はさておき、上記のコードで示したいことは、

  1. 入力されたテキストを加工してJSONの配列にする。
  2. JSONをパースして、JavaScript の配列を得る。
  3. 得られた配列の要素から、minimalな配列を拾い出すために再帰を使うことができる。
  4. 拾い出した minimalな配列 を分類する。

というステップを踏むのはいかがでしょうか?という考え方です。

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

投稿2019/08/02 01:51

編集2019/08/03 07:08
jun68ykt

総合スコア9058

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

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

jsrookie

2019/08/02 07:22

回答ありがとうございます! 段階を踏んで説明して頂けて動作が分かりやすかったです。 まだ完全に理解しきれていませんが、勉強を進めて必ず活用したいと思います。 本当にありがとうございます!
jun68ykt

2019/08/02 08:46

どういたしまして!コメントありがとうございます。 入力ファイルのテキストに、ちょっと手を加えるだけで JSON になるのであれば、 JSON.parse() でファイルの内容をそのまま保持した(javascriptの)配列が得られて、いろいろ楽に出来そうな気がしたので、上記のような回答を書きました。何か気になる点があればまたコメント頂ければと思います。
jun68ykt

2019/08/04 01:59

こちらのご質問、解決されましたでしょうか? ご質問と他の回答者さまからの回答も含め、回答を見直しましたが、もしかすると私の回答はまったく jsrookieさんの問題解決にはなっていなかったかもしれないと思っています。というのは、私の回答は、ご質問の意図として、 <input type="file" > で読み込むテキストファイルの内容が result4=[ [ [d,1], [b,2], [c,x], [d,y] ], [ [a,y], [b,x], [c,2], [d,1] ] ] というものだと解釈した回答になっていますが、この解釈自体、ご質問を誤読していたかもしれません。その場合は申し訳なかったです。
jsrookie

2019/08/06 04:25

ここ数日多忙で返事が遅くなってしまいました。 申し訳ございません。 JSONはまだあまり触れていないので今後疑問点が出た際は何卒よろしくお願いいたします。 また、読み込むファイルは配列ではなく 1 2 x y y x 2 1 のような文字間に改行やスペースを入れたようなものなのですが、読み込んだ文字列はプログラム上でresult4のような配列にする予定ですのでjun68ykt様の回答は今後改良していく上で活かしていきたいと考えています。 ありがとうございました。
jun68ykt

2019/08/06 11:41

ご返信ありがとうございます。多少なりともお役に立てましたようで、何よりです。
guest

0

連想配列でだいじょうぶでしょうか

javascript

1var result5 = []; 2for (var i = 0; i < result4.length; i++) { 3 for (var j = 0; j < result4[i].length; j++) { 4 k = result4[i][j][1]; 5 if (!result5[k]) { 6 result5[k] = []; 7 } 8 result5[k].push(result4[i][j]); 9 } 10}

投稿2019/08/01 23:27

takasima20

総合スコア7458

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

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

jsrookie

2019/08/01 23:47

回答ありがとうございます! 現在は教えて下さったプログラムを動かせる状況にないのですが、内容を読んだところ私の求めていたものにかなり近いと感じます。 動作が確認でき次第改めてお返事をさせていただきます。 本当にありがとうございます!
yokuda

2019/08/02 02:53

こんな感じに変更するという意味です。 これではマズいでしょうか。 result4=[ [ [a,1], [b,2], [c,x], [d,y] ], [ [a,y], [b,x], [c,2], [d,1] ] ] ↓ [a,1], [b,2], [c,x], [d,y], [a,y], [b,x], [c,2], [d,1]
guest

0

一次元にバラしてから処理するのはどうですか。
https://qiita.com/Toyoharu-Nishikawa/items/5faa1834926d67e5ac04

投稿2019/08/01 19:11

yokuda

総合スコア138

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

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

jsrookie

2019/08/01 20:04

回答ありがとうございます。 一応[a,1]などのa, b, c, dも意味のある情報なので1つの配列内に残しておきたいのですが、1次元にバラシてもa,b,c,dも一緒に分類できるでしょうか?
yokuda

2019/08/02 20:30

あ、すいません。 ↓のとこに回答を書いちゃいました・・・
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問