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

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

新規登録して質問してみよう
ただいま回答率
85.35%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

JavaScript

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

Q&A

解決済

1回答

2475閲覧

javascript でネストされた連想配列の値を書き換える

tama_yn0815

総合スコア143

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

JavaScript

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

配列

配列は、各データの要素(値または変数)が連続的に並べられたデータ構造です。各配列は添え字(INDEX)で識別されています。

0グッド

0クリップ

投稿2020/10/10 10:25

編集2020/10/12 02:50

javascript でネストされた連想配列の値を書き換える

実装レシピが浮かびません。
試した(実装中の)コードは記述します。
重要:ESscript5標準(IE11対応)

実現したいことのベタ処理(3階層分)

javascriipt

1// hasOwnPropertyとか除く・・・ 2(function (t, a, b, c, v) { 3 var arr = [a, b, c]; 4 var len = arr.length; 5 var idx = 0; 6 t[arr[0]][arr[1]][arr[2]] = v; 7 return t; 8})({a: {b: {c: '1'}}},'a','b','c','3'); 9// -> console: {a: {b: {c: '3'}}}

実際に書いているコード

javascript

1(function () { 2 function UserException (message, type) { 3 this.name = "UserException"; 4 this.message = message || 'Unexpected error information.'; 5 this.type = type || 'info'; 6 } 7 // 基底セッター&ゲッター 8 Function.prototype.setter = function(member, /*...multilayered, */value) {// -> member, multilayered, valueは実質使用しない....残余引数で対応したい 9 var _obj = this;// -> Class化されたオブジェクトに対応 10 // argumentsを通常配列化 11 var _args = Array.from(arguments); // -> ポリフィルを作成した(IEとか対応) 12 // ↓別の書き方...バグが有った際はこちらを使用すれば対応出来ると思われる。 13 //var _args = Array.prototype.slice.call(arguments); 14 //var _args =[].slice.call(arguments); 15 if (_args.length < 2) { 16 var msg = 'Unexpected execution: there are not enough arguments to execute ' + typeof this + '.'; 17 throw new UserException(msg, 'error'); // -> typeは列挙型にしたい 18 } 19 var changeAssignValue = _args.pop(); // -> _argsから最後の要素を削除し、変数[changeAssignValue]でキャッチする 20 var menberLayeredLength = _args.length; 21 var menberListIndex = 0; 22 var hasMenber = false; 23 var memberName = void(0); 24 while (menberListIndex < menberLayeredLength) { 25 memberName = _args[menberListIndex]; 26 hasMenber = _obj.hasOwnProperty(memberName); // -> _objではダメ。。1階層目以外書き換え不可 27 menberListIndex++; 28 if (hasMenber || menberLayeredLength == menberListIndex+1) {// -> 代入判定の条件は?? 29 // propertyの書き換え 30 Object.defineProperty(_obj, memberName, { value: changeAssignValue, writable: false, enumerable: true }); 31 } else { 32 // nothing 33 } 34 } 35 return _obj; 36 }; 37})()

最終的に出来上がったソースコード

javascriot

1(function () { 2 // 基底セッター 3 Object.prototype.setter = function(member, /*...multilayered, */value) {// -> member, multilayered, valueは実質使用しない....残余引数で対応したい 4 var obj = this;// -> Class化されたオブジェクトに対応 5 // 通常配列化 6 var _args = Array.from(arguments); // -> ポリフィルを作成した(IEとか対応) 7 if (_args.length < 2) { 8 var msg = 'Unexpected execution: there are not enough arguments to execute ' + typeof this + '.'; 9 throw new TypeError(msg); 10 } 11 var changeAssignValue = _args.pop(); // -> _argsから最後の要素を削除し、変数[changeAssignValue]でキャッチする 12 var menberKeyList = getMenberKeyList(_args.flat(1/0)); //-> _argsの中身を単配列化&階層を配列に詰める 13 var menberLayeredLength = menberKeyList.length; 14 var menberListIndex = 0; 15 var hasMenber = false; 16 var memberName = void(0); 17 var _obj = obj; // -> 処理用変数 18 var isLast = false; 19 while (menberListIndex < menberLayeredLength) { 20 isLast = (menberListIndex == menberLayeredLength - 1); 21 memberName = menberKeyList[menberListIndex]; 22 hasMenber = _obj.hasOwnProperty(memberName); // -> objではダメ。。1階層目以外書き換え不可 23 if (hasMenber) { 24 // 最後のindexのみ、propertyの書き換え 25 if (isLast) { 26 Object.defineProperty(_obj, memberName, { value: changeAssignValue, writable: false, enumerable: true }); 27 } 28 _obj = _obj[memberName]; 29 } else { 30 //_obj[memberName] = {};// -> 不用意なメンバー追加は避けた方が良いかも。。。 31 } 32 menberListIndex++; 33 } 34 return obj; 35 }; 36 // 念のため、列挙不可へ書き換え...jQueryUIの処理とバッティングする 37 Object.defineProperty(Object.prototype, 'setter', { value: Object.prototype.setter, writable: false, enumerable: false }); 38 39 // 基底ゲッター 40 Object.prototype.getter = function(member/*, ...multilayered*/){// -> m, multilayeredは実質使用しない....残余引数で対応 41 var obj = this;// -> Class化されたオブジェクトに対応 42 // 通常配列化 43 var _args = Array.from(arguments); // -> ポリフィルを作成した(IEとか対応) 44 if (_args.length < 1) { 45 var msg = 'Unexpected execution: there are not enough arguments to execute ' + typeof this + '.'; 46 throw new TypeError(msg); 47 } 48 var results = null; 49 var menberKeyList = getMenberKeyList(_args.flat(1/0)); //-> _argsの中身を単配列化&階層を配列に詰める 50 var menberLayeredLength = menberKeyList.length; 51 var menberListIndex = 0; 52 var hasMenber = false; 53 var memberName = void(0); 54 var _obj = obj; // -> 処理用変数 55 while (menberListIndex < menberLayeredLength) { 56 isLast = (menberListIndex == menberLayeredLength - 1); 57 memberName = menberKeyList[menberListIndex]; 58 hasMenber = _obj.hasOwnProperty(memberName); // -> objではダメ。。1階層目以外書き換え不可 59 if (hasMenber) { 60 if (isLast) { 61 results = _obj[memberName]; 62 } 63 _obj = _obj[memberName]; 64 } 65 menberListIndex++; 66 } 67 return results; 68 }; 69 // 念のため、列挙不可へ書き換え...jQueryUIの処理とバッティングする 70 Object.defineProperty(Object.prototype, 'getter', { value: Object.prototype.getter, writable: false, enumerable: false }); 71 72 // Array[ポリフィル:IE11対応] 73 Object.defineProperty(Array.prototype, 'flat', { writable: false, enumerable: false, value: (function (){ 74 return (Array.prototype.flat) ? Array.prototype.flat : function (deepth) { 75 var _arr = this; 76 if (isNaN(deepth)) { deepth = 1; } 77 return deepth > 0 ? _arr.reduce(function (acc, val) { 78 return acc.concat(Array.isArray(val) ? val.flatDeep(deepth - 1) : val); 79 }, []) : _arr.slice(); 80 }; 81 })()}); 82 Object.defineProperty(Array, 'from', { writable: false, enumerable: false, value: (function () { 83 return (Array.from) ? Array.from : function (arrayLike/*, mapFn, thisArg */) { 84 var arr = this; 85 var items = Object(arrayLike); 86 if (arrayLike == null) { 87 throw new TypeError('Array.from requires an array-like object - not null or undefined'); 88 } 89 var mapFn = arguments.length > 1 ? arguments[1] : void undefined;// -> 受け取った場合はそれを使う 90 var _this; 91 if (typeof mapFn !== 'undefined') { 92 if (!isCallable(mapFn)) { 93 throw new TypeError('Array.from: when provided, the second argument must be a function'); 94 } 95 if (arguments.length > 2) { 96 _this = arguments[2]; 97 } 98 } 99 var len = toLength(items.length); 100 var Arr = isCallable(arr) ? Object(new arr(len)) : new Array(len); 101 var index = 0; 102 var item; 103 while (index < len) { 104 item = items[index]; 105 if (mapFn) { 106 Arr[index] = typeof _this === 'undefined' ? mapFn(item, index) : mapFn.call(_this, item, index); 107 } else { 108 Arr[index] = item; 109 } 110 index += 1; 111 } 112 Arr.length = len; 113 return Arr; 114 }; 115 // 秘匿関数 116 function isCallable (fn) { 117 return typeof fn === 'function' || Object.prototype.toString.call(fn) === '[object Function]'; 118 } 119 function toInteger (value) { 120 var number = Number(value); 121 if (isNaN(number)) { 122 return 0; 123 } 124 if (number === 0 || !isFinite(number)) { 125 return number; 126 } 127 return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); 128 } 129 function toLength (value) { 130 var maxSafeInteger = Math.pow(2, 53) - 1; // 2^53-1 約9千兆 131 var len = toInteger(value); 132 return Math.min(Math.max(len, 0), maxSafeInteger); 133 }; 134 })()}); 135 136 /** 秘匿関数 */ 137 // 階層を順番に並び替えて返却(単配列化) 138 function getMenberKeyList (obj) { 139 return (!Array.isArray(obj) || obj.length < 1) ? [] : (function (r, o) { 140 var i = 0; 141 while (i < o.length) { 142 var k = o[i]; 143 if (Array.isArray(k)) { k = k.flat(1/0).join('.'); } 144 if (typeof k != 'string') { k = k.toString(); } 145 k = k.split('.'); 146 r = r.concat(k); 147 i++; 148 } 149 return r; 150 })([], obj); 151 } 152 /** under test code */ 153154 // -> test code setter by type Array. 155 var nestedArray = [[[[[[1,2,3]]]]]]; 156 console.log(nestedArray.setter('0.0.0.0.0.1',5)); // -> [0: [0: [0: [0: [0: [0: 1. 1: 5, 2: 3]]]]]]; 157 // -> test code setter by type Object. 158 var nestedObject = {a: {b: {c: {d: {e: 'hoge', z: 'fuga'}}}}}; 159 console.log(nestedObject.setter('a.b','c',['d','e'],'hogehoge')); // -> {a: {b: {c: {d: {e: 'hogehoge', z: 'fuga'}}}}}; 160 // -> test code setter by type Instance. 161 var _func = function _func () { this.mem1 = {mem2: {mem3: {mem4: {mem5: 'member5', mem6: 'member6'}}}}; }; 162 var nestedPropIns = new _func(); 163 console.log(nestedPropIns.setter('mem1.mem2.mem3.mem4.mem5', '12345')); // -> _func: {mem1: {mem2: {mem3: {mem4: {mem5: '12345', mem6: 'member6'}}}}}; 164165 // -> test code getter by type Array. 166 console.log(nestedArray.getter('0.0.0.0.0.1'));// -> 5 167 console.log(nestedArray.getter('0.0.0.0.0.4'));// -> null 168 // -> test code getter by type Object. 169 console.log(nestedObject.getter('a.b','c',['d','e'])); // -> hogehoge 170 console.log(nestedObject.getter('a.b','c',['d','j'])); // -> null 171 // -> test code getter by type Instance. 172 console.log(nestedPropIns.getter('mem1.mem2.mem3.mem4.mem5')); // -> 12345 173 console.log(nestedPropIns.getter('mem1.mem2.mem3.mem5.mem5')); // -> null 174})();

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは

ご質問にある、

実現したいことのベタ処理(3階層分)

を、任意の階層のプロパティで行うために、ライブラリの力を借りるのはいかがでしょうか?

重要:ESscript5標準(IE11対応)

とのことですが、オブジェクトや配列の操作で便利なライブラリ lodash は、

Support

Tested in Chrome 74-75, Firefox 66-67, IE 11, Edge 18, Safari 11-12, & Node.js 8-12.

とあるように IE 11 もサポートしています。この lodash が提供するメソッドの _.set を使えば、任意の階層のプロパティを文字列の配列で指定することで、その値を変更できます。以下、使用例です。

javascript

1// 3階層 2const obj = {a: {b: {c: '1'}}}; 3 4console.log(obj.a.b.c); // => '1' 5 6_.set(obj, ['a', 'b', 'c'], '3'); 7 8console.log(obj.a.b.c); // => '3' 9 10 11 12// 5階層 13const obj2 = {a: {b: {c: {d: {e: '10'}}}}}; 14 15console.log(obj2.a.b.c.d.e); // => '10' 16 17_.set(obj2, ['a', 'b', 'c', 'd', 'e'], '30'); 18 19console.log(obj2.a.b.c.d.e); // => '30' 20 21 22

補足

  • 上記の _.set と対になるメソッドとして、値の取得は _.get として提供されています。

投稿2020/10/10 20:12

編集2020/10/11 00:16
jun68ykt

総合スコア9058

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

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

tama_yn0815

2020/10/11 09:55

ご回答をいただきまして、ありがとうございますっ! すみません。。。今回の要件を予め記述していませんでした。。。 libraryの使用が、ライセンス上の都合で使用できないのです。 jQueryのAPIを含め、必要な機能を必要な分だけ自分たちで用意する必要があるのでした。。。 ですが、回答を拝見して、lodashの"_.set"メソッドは内部を追ってみても良いかもです。
jun68ykt

2020/10/11 13:16

コメントありがとうございます。 > libraryの使用が、ライセンス上の都合で使用できないのです。 なるほどですね。 lodash の _,set は与えるpath が配列でも文字列でもよかったり、配列のインデクスに相当する数字が含まれていると、それをよしなに解釈してくれる優れモノですが、そこまでのものでなくても、回答に挙げたサンプルコードの中で、lodashの_.set の替わりになるだけの関数であれば、そんなに大変なものにはならないと思いましたので、自作してみました。以下 https://codepen.io/jun68ykt/pen/gOMpRPR?editors=0012 の function setByPath(obj, path, value) です。簡易的なものですが、参考になれば幸いです。
tama_yn0815

2020/10/11 17:56

こちらのコメントの回答を参考に組み上げてみました! ありがとうございますっ!
jun68ykt

2020/10/11 20:56

どういたしまして > こちらのコメントの回答を参考に組み上げてみました! とのことでよかったです????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問