Javascript - конвертировать вложенные массивы в объект массивов - PullRequest
0 голосов
/ 08 ноября 2018

У меня есть вложенный массив с неизвестной формой. Вот пример:

["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
]

Все массивы имеют длину 2 или больше. Массив может содержать любое количество других массивов, которые также могут содержать любое количество массивов. Все значения являются строками или массивами.

Я пытаюсь преобразовать это в один объект со следующей формой:

{"head": ["val1","val2","val3", 
    {"head2": ["val4","val5", 
        {"head3": ["val6","val7", 
            {"head4": ["val8"]}, "val9"]},
    {"head5": ["val10", "val11"]}
]}

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

Ответы [ 6 ]

0 голосов
/ 08 ноября 2018

Поскольку вы пометили это как lodash, здесь также есть краткое решение:

var data = ["head","val1","val2","val3", ["head2","val4","val5", ["head3","val6","val7", ["head4", "val8"],"val9"]], ["head5", "val10", "val11"] ]

const f = (d) => ({[_.head(d)]: _.map(_.tail(d), x => _.isArray(x) ? f(x) : x)})

console.log(f(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Это рекурсивное решение, использующее lodash .head для получения первого элемента массива, .tail , чтобы получить все, кроме первого, а затем _.map, чтобы пройти через каждый из элементов и вернуть массив.

0 голосов
/ 08 ноября 2018

Этот эффективный подход позволяет избежать использования slice() (что приведет к созданию временного массива размера N-1, который будет отброшен):

function change(a) {
  let b = [];
  for (let i = 1; i < a.length; i++) {
    let v = a[i];
    b.push(Array.isArray(v) ? change(v) : v);
  }
  return {[a[0]]: b};
}

console.log(change(
  ["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
  ]
));
0 голосов
/ 08 ноября 2018

Как то так?

function convert(arr) {
  if (arr instanceof Array) {
    const [key, ...values] = arr;
    return { [key]: values.map(convert) };
  } else {
    return arr;
  }
}

const test = ["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
];

console.log(convert(test));
0 голосов
/ 08 ноября 2018

ES6: Вы можете сделать что-то вроде следующего

function convertArrayToObject(arr) {
  return Array.isArray(arr) && arr.length ? {
    [arr[0]]: arr.slice(1).map(convertArrayToObject)
  } : arr;
}

Этот код определяет функцию convertArrayToObject, которая возвращает сам элемент, если он не является массивом, или устанавливает первый элемент в качестве ключа и вызывает функцию, если с оставшимися элементами в качестве значений, если это массив.

0 голосов
/ 08 ноября 2018

Просто сделайте это рекурсивно так:

function convert(arr) {
  return {
    [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item)
  }
}

Функция convert возвращает объект, связывающий одну пару ключ-значение. Ключом является arr[0], а значением являются остальные элементы в массиве (arr.slice(1)), отображенные в новый массив, так что convert вызывается для всех элементов массива в этом массиве.

ES5 Версия:

function convert(arr) {
  var obj = {};
  obj[arr[0]] = arr.slice(1).map(function(item) {
      return item instanceof Array? convert(item): item;
  });
  return obj;
}

Пример:

function convert(arr) {
  return {
    [arr[0]]: arr.slice(1).map(item => Array.isArray(item)? convert(item): item)
  }
}

let arr = ["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
];

let result = convert(arr);

console.log(result);
0 голосов
/ 08 ноября 2018

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

В базовом случае вашей рекурсивной функции ввод не является массивом, поэтому просто верните ввод.

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

var a = ["head","val1","val2","val3",
    ["head2","val4","val5",
        ["head3","val6","val7", 
            ["head4", "val8"],"val9"]],
    ["head5", "val10", "val11"]
];

function convert(val) {
  var result;
  if (Array.isArray(val)) {
    var key = val[0];
    var vals = val.slice(1);
    result = {};
    result[key] = [];
    for (var i = 0; i < vals.length; i++) {
      result[key].push(convert(vals[i]));
    }
  } else {
    result = val;
  }
  return result;
}

console.log(convert(a));
...