Table of Contents
環境
- JavaScript (es5)
今回したいこと
- ドットで区切ったキーがあって、値がある
- ドットで区切ったキーはドットの部分でネストしたオブジェクトにしたい
- キー、値が複数ありネストしたオブジェクトのマージもしたい
元の値
キー | 値 |
---|---|
keyA-0.keyA-1.keyA-2 | valAAA |
keyA-0.keyA-1.keyB-2 | valAAB |
keyB-0.keyB-1.keyB-2 | valBBB |
keyB-0.keyC-1.keyC-2 | valBCC |
期待値
{
keyA-0: {
keyA-1: {
keyA-2:"valAAA",
keyB-2:"valAAB"
}
},
keyB-0: {
keyB-1: {
keyB-2:"valBBB"
},
keyC-1: {
keyC-2:"valBCC"
}
}
}
ネストしたオブジェクトを生成してマージをする関数
const AAAKeyStr = 'keyA-0.keyA-1.keyA-2';
const AAAKey = AAAKeyStr.split('.'); // ドット区切って配列にする
const AAAVal = 'valAAA';
const AABKeyStr = 'keyA-0.keyA-1.keyB-2'
const AABKey = AABKeyStr.split('.'); // ドット区切って配列にする
const AABVal = 'valAAB'
const BBBKeyStr = 'keyB-0.keyB-1.keyB-2'
const BBBKey = BBBKeyStr.split('.'); // ドット区切って配列にする
const BBBVal = 'valBBB'
const BCCKeyStr = 'keyB-0.keyC-1.keyC-2'
const BCCKey = BCCKeyStr.split('.'); // ドット区切って配列にする
const BCCVal = 'valBCC';
/**
* キー配列からネストしたオブジェクトを作成しながらマージ
*/
const createNestObj = (obj, keys, val, idx = 0) => {
if (keys.length === idx) return val;
if (!obj[keys[idx]]) {
obj[keys[idx]] = {};
}
obj[keys[idx]] = createNestObj(obj[keys[idx]], keys, val, ++idx);
return obj;
}
// AAAKeyとAAAValでオブジェクトを作る
let data = createNestObj({}, AAAKey, AAAVal);
console.log(data);
// AABKeyとAABValでオブジェクトを生成してマージ ※第一引数には上記作成したオブジェクトのdata変数を利用
data = createNestObj(data, AABKey, AABVal);
console.log(data);
// BBBKeyとBBBValでオブジェクトを生成してマージ ※第一引数には上記作成したオブジェクトのdata変数を利用
data = createNestObj(data, BBBKey, BBBVal);
console.log(data);
// BCCKeyとBCCValでオブジェクトを生成してマージ ※第一引数には上記作成したオブジェクトのdata変数を利用
data = createNestObj(data, BCCKey, BCCVal);
console.log(data);
出力結果
- 段階的にみるとマージされているのがわかる
1回目のログ
{
keyA-0: {
keyA-1: {
keyA-2:"valAAA"
}
}
}
2回目のログ
{
keyA-0: {
keyA-1: {
keyA-2:"valAAA",
keyB-2:"valAAB"
}
}
}
3回目のログ
{
keyA-0: {
keyA-1: {
keyA-2:"valAAA",
keyB-2:"valAAB"
}
},
keyB-0: {
keyB-1: {
keyB-2:"valBBB"
}
}
}
4回目のログ
{
keyA-0: {
keyA-1: {
keyA-2:"valAAA",
keyB-2:"valAAB"
}
},
keyB-0: {
keyB-1: {
keyB-2:"valBBB"
},
keyC-1: {
keyC-2:"valBCC"
}
}
}
結果について
- 同じキーの値は同じオブジェクトに格納されている。
- 重複したキー、値の場合は後勝ちで上書きされます。
reduceを使ってネストしたオブジェクトをマージしてみる
- reduceを使いたいので、先ほどの値から以下のような配列をあらかじめ作った。
const keyValArr = [
{
key: 'keyA-0.keyA-1.keyA-2',
val: 'valAAA',
},
{
key: 'keyA-0.keyA-1.keyA-2',
val: 'valAAB',
},
{
key: 'keyB-0.keyB-1.keyB-2',
val: 'valBBB',
},
{
key: 'keyB-0.keyC-1.keyC-2',
val: 'valBCC',
},
];
/**
* 先ほどの配列とまったく同じ
* ネストしたオブジェクトを作成しながらマージ
*/
const createNestObj = (obj, keys, val, idx = 0) => {
if (keys.length === idx) return val;
if (!obj[keys[idx]]) {
obj[keys[idx]] = {};
}
obj[keys[idx]] = createNestObj(obj[keys[idx]], keys, val, ++idx);
return obj;
}
// 配列を回しながらマージする。※reduceの初期値は空のオブジェクト
const data = keyValArr.reduce((a, c) => {
// ドットで区切って配列にする
const cArr = c.key.split('.');
// 再帰的にネストしたオブジェクトを呼び出す
return createNestObj(a, cArr, c.val);
},{});
// 出力
console.log(data);