Javascript: строки обозначений точек для ссылок на вложенные объекты - PullRequest
1 голос
/ 07 июля 2019

Мы пытаемся установить значения вложенных объектов на основе строк точечной записи.

Пример ввода:

{
    "bowtime": [
       "30",
       " 1",
       " 3",
       " 20"
    ],
    "bowstate.levi.leviFlo.totalFloQuot": ".95",
    "bowstate.crem.cremQuot": "79" 
}

Требуемый вывод:

{
    "bowstate": {
       "levi": {
           "leviFlo": {
               "totalFloQuot": 0.95
           }
       },
       "crem": {
           "cremQuot": 79
       }
    },
    "bowtime": [
       "30",
       " 1",
       " 3",
       " 20"
    ],
}

Пока код работает нормально, но кажется слишком сложным и допускает только 4 слоявложенности.Как мы можем упростить этот код и заставить его работать для ссылок с более чем 4 уровнями вложенности:

const dayspace = {};
var keyArr = Object.keys(input);

for (key in keyArr) {
  if ( keyArr[key].indexOf('.') > -1 ) {
    var setArr = keyArr[key].split('.');
    dayspace[setArr[0]] = dayspace[setArr[0]] || {}
    for (var s = 0; s < setArr.length; s++) {
      if (s == 1) {
        if (setArr.length > s + 1) dayspace[setArr[0]][setArr[s]] = {}
        else dayspace[setArr[0]][setArr[s]] = req.body[keyArr[key]]
      }
      if (s == 2) {
        if (setArr.length > s + 1) dayspace[setArr[0]][setArr[1]][setArr[s]] = {}
        else dayspace[setArr[0]][setArr[1]][setArr[s]] = req.body[keyArr[key]]
      }
      if (s == 3) {
        if (setArr.length > s + 1) dayspace[setArr[0]][setArr[1]][setArr[2]][setArr[s]] = {}
        else dayspace[setArr[0]][setArr[1]][setArr[2]][setArr[s]] = req.body[keyArr[key]]
      }
      if (s == 4) dayspace[setArr[0]][setArr[1]][setArr[2]][setArr[3]][setArr[s]] = req.body[keyArr[key]]
    }
  }
  else {
    dayspace[keyArr[key]] = req.body[keyArr[key]]
  }
}

Ответы [ 4 ]

2 голосов
/ 07 июля 2019

Я бы разделил ключ на . и использовал бы reduce, чтобы создать все, кроме последнего вложенного значения, если необходимо, а затем назначил бы значение последнему объекту, созданному или найденному в обратном вызове Reduce:

const input = {
    "bowtime": [
       "30",
       " 1",
       " 3",
       " 20"
    ],
    "bowstate.levi.leviFlo.totalFloQuot": ".95",
    "bowstate.crem.cremQuot": "79" 
};

const output = Object.entries(input).reduce((outerObj, [key, val]) => {
  if (!key.includes('.')) {
    outerObj[key] = val;
    return outerObj;
  }
  const keys = key.split('.');
  const lastKey = keys.pop();
  const lastObj = keys.reduce((a, key) => {
    // Create an object at this key if it doesn't exist yet:
    if (!a[key]) {
      a[key] = {};
    }
    return a[key];
  }, outerObj);
  // We now have a reference to the last object created (or the one that already existed
  // so, just assign the value:
  lastObj[lastKey] = val;
  return outerObj;
}, {});
console.log(output);
1 голос
/ 07 июля 2019

Вы можете использовать более короткий подход, используя функцию для разделения пути к значению и генерировать новые объекты для него.

function setValue(object, path, value) {
    var last = path.pop();
    path.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}

var object = { bowtime: ["30", " 1", " 3", " 20" ], "bowstate.levi.leviFlo.totalFloQuot": ".95", "bowstate.crem.cremQuot": "79" };

Object.entries(object).forEach(([key, value]) => {
    if (!key.includes('.')) return;
    setValue(object, key.split('.'), value);
    delete object[key];
});

console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
1 голос
/ 07 июля 2019

Я делал подобные вещи в своем проекте. Я добился этого с помощью популярного пакета под названием Flat. Ссылка: https://github.com/hughsk/flat

var unflatten = require('flat').unflatten

unflatten({
    'three.levels.deep': 42,
    'three.levels': {
        nested: true
    }
})

// {
//     three: {
//         levels: {
//             deep: 42,
//             nested: true
//         }
//     }
// }

Этот пакет может сделать вашу вложенную структуру плоской и уплощенной. Там есть и другие полезные методы. Так что это будет более гибким.

Я думаю, вы должны использовать его, что приведет к уменьшению количества ошибок в вашем проекте.

0 голосов
/ 07 июля 2019

Вы можете использовать Object.entires, чтобы получить массив пар ключ-значение в вашем объекте, а затем .reduce() ключи вашего объекта, используя .split("."), чтобы получить свойства одиночного объекта в массив, который затем можно использовать для построения Ваш новый объект:

const obj = {
  "bowtime": [
    "30",
    " 1",
    " 3",
    " 20"
  ],
  "bowstate.levi.leviFlo.totalFloQuot": ".95",
  "bowstate.crem.cremQuot": "79"
};

const res = Object.entries(obj).reduce((acc, [k, v]) => {
  const keys = k.split('.');
  let cur = acc;
  keys.length > 1 && keys.forEach(ka => {
    cur[ka] = cur[ka] || {};
    cur = cur[ka];
  });
  cur[keys.pop()] = v;
  return acc;
}, {});

console.log(res);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...