通过JavaScript将数组转换为JSON对象

8

我卡在了解决这个问题上。 将下面的数组转换

var input = [
    'animal/mammal/dog',
    'animal/mammal/cat/tiger',
    'animal/mammal/cat/lion',
    'animal/mammal/elephant',
    'animal/reptile',
    'plant/sunflower'
]

转换为 JSON 对象

var expectedResult = {
 "animal": {
  "mammal": {
   "dog": true,
   "cat": {
    "tiger": true,
    "lion": true
   },
   "elephant": true
  },
  "reptile": true
 },
 "plant": {
  "sunflower": true
 }
}

我应该使用哪种数据结构和算法呢?谢谢。


"JSON对象"?你是指JavaScript对象吧?JSON是一种格式。 - phuzi
我的意思是该对象的格式类似于JSON。 :) - Le Duc Anh
它不是一个特定的JavaScript对象,而是一个普通的JavaScript对象。 - PA.
你应该阅读关于字符串迭代、创建对象以及递归地创建对象内部对象的资料,这并不像听起来那么难。 - PA.
5个回答

4

你需要先将每个元素进行split操作,以转换成数组。

使用reversereduce方法,可以将它们转换为对象。

最后一步是合并这些对象。

Lodash.js 的合并方法是其中的一种方式。

var input = ['animal/mammal/dog','animal/mammal/cat/tiger','animal/mammal/cat/lion', 'animal/mammal/elephant','animal/reptile', 'plant/sunflower']
var finalbyLodash={}
input.forEach(x=>{
  const keys = x.split("/");
  const result = keys.reverse().reduce((res, key) => ({[key]: res}), true);
  finalbyLodash = _.merge({}, finalbyLodash, result);
});
console.log(finalbyLodash);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>


3
为了更易理解问题,将其分解成若干部分。
第一步是将每个字符串转换为可用的内容,将以下内容进行转换:
"animal/mammal/dog"

转化为:

[ "animal", "mammal", "dog" ]

这是一个用于构建最终对象所需的属性名称数组。

两个函数可以为您完成此操作,String.prototype.split() 用于将字符串拆分成数组,Array.prototype.map() 用于转换数组中的每个元素:

let splitIntoNames = input.map(str => str.split('/'));

中间结果如下:
[
  [ "animal", "mammal", "dog" ],
  [ "animal", "mammal", "cat", "tiger" ],
  [ "animal", "mammal", "cat", "lion" ],
  [ "animal", "mammal", "elephant" ],
  [ "animal", "reptile" ],
  [ "plant", "sunflower" ]
]

下一步是迭代每个数组,使用Array.prototype.forEach()为对象添加属性。你可以使用for循环向对象添加属性,但让我们使用递归函数addName()来完成这个任务:
function addName(element, list, index) {
  if (index >= list.length) {
    return;
  }
  let name = list[index];
  let isEndOfList = index === list.length - 1;

  element[name] = element[name] || (isEndOfList ? true : {});

  addName(element[name], list, index + 1);
}

let result = {};
splitIntoNames.forEach((list) => {
  addName(result, list, 0);
});

结果如下:
result: {
  "animal": {
    "mammal": {
      "dog": true,
      "cat": {
        "tiger": true,
        "lion": true
      },
      "elephant": true
    },
    "reptile": true
  },
  "plant": {
    "sunflower": true
  }
}

const input = [
  "animal/mammal/dog",
  "animal/mammal/cat/tiger",
  "animal/mammal/cat/lion",
  "animal/mammal/elephant",
  "animal/reptile",
  "plant/sunflower",
];

let splitIntoNames = input.map((str) => str.split("/"));
console.log("splitIntoNames:", JSON.stringify(splitIntoNames, null, 2));

function addName(element, list, index) {
  if (index >= list.length) {
    return;
  }
  let name = list[index];
  let isEndOfList = index === list.length - 1;

  element[name] = element[name] || (isEndOfList ? true : {});

  addName(element[name], list, index + 1);
}

let result = {};
splitIntoNames.forEach((list) => {
  addName(result, list, 0);
});
console.log("result:", JSON.stringify(result, null, 2));


@LeDucAnh 非常感谢,我很高兴能够帮助你。你会接受这个答案吗? - terrymorse
是的,它很完美。不再有任何疑问了。 :) - Le Duc Anh

1

我尝试使用数组reduce,希望它有所帮助

let input = [
  "animal/mammal/dog",
  "animal/mammal/cat/tiger",
  "animal/mammal/cat/lion",
  "animal/elephant",
  "animal/reptile",
  "plant/sunflower",
];

let convertInput = (i = []) =>
  i.reduce((prev, currItem = "") => {
    let pointer = prev;
    currItem.split("/").reduce((prevPre, currPre, preIdx, arrPre) => {
      if (!pointer[currPre]) {
        pointer[currPre] = preIdx === arrPre.length - 1 ? true : {};
      }
      pointer = pointer[currPre];
    }, {});
    return prev;
  }, {});

console.log(JSON.stringify(convertInput(input), null, 4));


1

晚到派对了,这是我的尝试。我正在实现递归方法:

var input = ['animal/mammal/dog', 'animal/mammal/cat/tiger', 'animal/mammal/cat/lion', 'animal/mammal/elephant', 'animal/reptile', 'plant/sunflower'];

result = (buildObj = (array, Obj = {}) => {
  array.forEach((val) => {
    keys = val.split('/');
    (nestedFn = (object) => {
      outKey = keys.shift();
      object[outKey] = object[outKey] || {};
      if (keys.length == 0) object[outKey] = true;
      if (keys.length > 0) nestedFn(object[outKey]);
    })(Obj)
  })
  return Obj;
})(input);

console.log(result);


1
您可以创建一个函数,通过"/"将数组中的每个元素切片,然后将结果放入变量中,最后只需组装Json。我的意思是像下面这样的东西:

    window.onload = function() {
      var expectedResult;
      var input = [
        'animal/mammal/dog',
        'animal/mammal/cat/tiger',
        'animal/mammal/cat/lion',
        'animal/mammal/elephant',
        'animal/reptile',
        'plant/sunflower'
    ]

      input.forEach(element => {
        var data = element.split('/');

        var dog = data[2] === 'dog' ? true : false
        var tiger = data[2] === 'cat' && data[3] === 'tiger'  ? true : false
        var lion = data[2] === 'cat' && data[3] === 'lion'  ? true : false


        expectedResult = {
          data[0]: {
            data[1]: {
             "dog": dog,
             "cat": {
              "tiger": tiger,
              "lion": lion
             }
            }
          }
        }
      })
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接