【问题标题】:How to convert an array of paths to an object in Javascript? [duplicate]如何在Javascript中将路径数组转换为对象? [复制]
【发布时间】:2021-11-16 06:42:18
【问题描述】:

我有一个路径数组:

const paths = [
    "/path/to/first",
    "/path/to/second",
    "/path/to/third",
    "/path/from/first",
    "/path/from/second",
    "/users/bill",
    "/users/john"
];

我想将其转换为这种形式的 javascript 对象:

{
    path: {
        to: {
            first,
            second,
            third
        },
        from: {
            first,
            second
        }
    },
    users: {
        bill,
        john
    }
}

我将如何使用纯 javascript(不是 jQuery,而不是使用 JSON.parse 或其他快捷方式)来做到这一点。

如有必要,端点可以是指向“null”的键:值对,例如:

user: {
     bill: null,
     john: null
}

我希望有一个非递归的解决方案,但如果这通过递归明显更简单,那没关系!

【问题讨论】:

  • 你试过什么? JSON.parse 是“纯”JavaScript,不确定您所说的快捷方式是什么意思,并且首先不适用于该问题。

标签: javascript arrays recursion


【解决方案1】:

您应该使用分隔符/ 分割字符串,这应该会为数组中的第一个路径生成一个类似['', 'path', 'to', 'first'] 的数组。那么它就像检查path是否在数组中一样简单,如果是,则to在数组中,如果是,则将first添加到obj.path.to。

类似的东西(这可以重构更多,这是第 0 次尝试)

const obj = {
  path: {
    to: {
    },
    from: {
    }
  },
  users: {
  }
}
for (let path of paths) {
  const pathArr = path.split('/');
  if (pathArr.includes('path') && pathArr.includes('to')) {
    obj.path.to[pathArr[3]] = null;
  }
  else if (pathArr.includes('path') && pathArr.includes('from')) {
    obj.path.from[pathArr[3]] = null;
  }
  ...
}

等等。

显然这可以提高效率,动态创建键 pathtofromusers,但这会起作用

【讨论】:

    【解决方案2】:

    这是一个简单的方法。它最多只能处理三个。如果需要,您可以尝试扩展它。

    const paths = [
      "/path/to/first",
      "/path/to/second",
      "/path/to/third",
      "/path/from/first",
      "/path/from/second",
      "/users/bill",
      "/users/john"
    ];
    
    const res = paths.reduce((acc, path) => {
      const [first, second, third] = path.split("/").filter((a) => a);
      if (first && !acc[first]) acc[first] = {};
      if (second && !acc[first][second]) acc[first][second] = {};
      if (third && !acc[first][second][third]) acc[first][second][third] = {};
      return acc;
    }, {});
    
    console.log(res);

    【讨论】:

      【解决方案3】:

      这是一个基于一些简单辅助函数构建的版本:

      const setPath = ([p, ...ps]) => (v) => (o) =>
        p == undefined ? v : Object .assign (
          Array .isArray (o) || Number .isInteger (p) ? [] : {},
          {...o, [p]: setPath (ps) (v) ((o || {}) [p])}
        )
      
      const hydrate = (xs) =>
        xs .reduce ((a, [p, v]) => setPath (p) (v) (a), {})
      
      const build = (ps) => 
        hydrate (ps .map (p => [p .slice (1) .split ('/'), null]))
      
      const paths = ["/path/to/first", "/path/to/second", "/path/to/third", "/path/from/first", "/path/from/second", "/users/bill", "/users/john"]
      
      console .log (build (paths))
      .as-console-wrapper {max-height: 100% !important; top: 0}

      在这里,setPath 采用诸如 ['path', 'to', 'first'], and a value such as 'null' and an object and returns a copy of that object, setting the value at that path, creating any intermediate nodes as needed. hydrate 之类的路径,采用路径-值对数组并根据需要创建一个全新的对象。

      我们的build 函数然后拆分"/" 上的路径,将每个路径映射到[['path', 'to', 'first'], null] 样式的条目,然后将结果数组传递给hydrate

      递归使这段代码更简单。我们可以用更命令式的方式编写setPath,使用迭代与递归,但我希望代码更丑陋,但收益甚微。不过,我很想被证明是错误的。

      【讨论】:

      • 似乎关闭这个问题的权力在这里“已经回答”:stackoverflow.com/questions/34054601/… ...这很奇怪,因为在我看来我的问题有很大的不同,一个是如果我有多个路径,我需要将这些额外的路径包含在同一个 javascript 对象中。其他帖子中的 reduce 功能似乎无法解决该问题。
      • 虽然这可能不是正确的副本,但肯定有很多这样的问题。我的答案中的工具是为响应other similar problems 而创建的。但是第二轮减少会将其转换为解决您的解决方案的解决方案。我的最里面的部分使用递归而不是减少,但两者都可以。最后,“权力”是那些努力保持这个最好的编程问答网站可用的人。关闭重复项是其中的重要组成部分。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-29
      • 2020-05-02
      • 2016-12-13
      • 2021-05-27
      • 1970-01-01
      相关资源
      最近更新 更多