展平对象和限制嵌套数量 [英] Flattening object and limitting number of nesting

查看:43
本文介绍了展平对象和限制嵌套数量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想限制对象内扁平结构的数量.考虑下面的例子.

输入:

const exampleObj = {富:{酒吧: {商务:你好"}}};

输出:

{foo_bar_biz: 你好"}

我想设置一个限制器(limit = 2),这样函数将停止执行递归函数并返回类似这样的东西

{foo_bar: [Object] 对象"}

这是一个片段:

const { useState, useEffect} = React;const exampleObj = {富:{酒吧: {商务:你好"}}};让限制= 0;功能应用(){const [state, setState] = useState({});useEffect(() => {展平(exampleObj);}, []);const flatten = (data, parent, result = {}) =>{for(让输入数据){const propName = 父级?parent + "_" + key : key;if (typeof data[key] === "object") {限制++;如果(限制 <= 1){展平(数据[键],道具名称,结果);} 别的 {setState(prevState => {返回 {...prevState,[道具名称]:typeof data[key] === "object" ?[对象] 对象":数据[键]};});}} 别的 {结果[propName] = 数据[key];设置状态({...状态,[道具名称]:数据[键]});}}};控制台日志(状态);返回 (<div><p>开始编辑以看到一些神奇的事情发生:)</p>

);}ReactDOM.render(, document.getElementById("root"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script><div id="root"></div>

我已经为此准备了一个解决方案,但它非常麻烦.https://stackblitz.com/edit/react-u5klvc

解决方案

这是 flatten 的一种可能实现.注意它是如何与 React 或特定的 React 组件完全分离的.它适用于任何 JavaScript 对象 -

const snakecase = s =>s.join(_")const flatten = (t = {}, n = Infinity, join = snakecase) =>{ const many = (t, n, path) =>n >= 0 &&对象(t) === t?Object.entries(t).flatMap(_ => one(_, n - 1, path)): [ [ 加入(路径), t ] ]const one = ([ k, v ], n, path) =>许多(v,n,[...路径,k])返回 Object.fromEntries(many(t, n, []))}

举一些例子data -

const data ={ a1: 11, a2: { b1: 21, b2: 22 }, a3: { b1: { c1: 311, c2: 312 }, b2: { c1: 321, c2: 322, c3: { d1: 3231 } }}}

1depth 压平一层 -

flatten(data, 1)

{a1":11,a2_b1":21,a2_b2":22,a3_b1":{c1":311,c2":312},a3_b2":{c1":321,c2":322,c3":{d1":3231}}}

2depth 压平了两个级别 -

flatten(data, 2)//=>...

{a1":11,a2_b1":21,a2_b2":22,a3_b1_c1":311,a3_b1_c2":312,a3_b2_c1":321,a3_b2_c2":322,a3_b2_c3":{d1":3231}}

默认depth是无穷大-

flatten(data)//=>...

{a1":11,a2_b1":21,a2_b2":22,a3_b1_c1":311,a3_b1_c2":312,a3_b2_c1":321,a3_b2_c2":322,a3_b2_c3_d1":3231}

默认的join是snakecase,但是可以在调用点指定参数-

const camelCase = ([ first = "", ...rest ]) =>first + rest.map(upperFirst).join("")const upperFirst = ([ first = "", ...rest ]) =>first.toUpperCase() + rest.join("")扁平化(数据,2,驼峰式)//=>...

{a1":11,a2B1":21,a2B2":22,a3B1C1":311,a3B1C2":312,a3B2C1":321,a3B2C2":322,a3B2C3":{d1":3231}}

展开下面的代码片段以在您自己的浏览器中验证结果 -

const data ={ a1: 11, a2: { b1: 21, b2: 22 }, a3: { b1: { c1: 311, c2: 312 }, b2: { c1: 321, c2: 322, c3: { d1: 3231 } }}}const snakecase = s =>s.join("_")const flatten = (t = {}, n = Infinity, join = snakecase) =>{ const many = (t, n, path) =>n >= 0 &&对象(t) === t?Object.entries(t).flatMap(_ => one(_, n - 1, path)): [ [ 加入(路径), t ] ]const one = ([ k, v ], n, path) =>许多(v,n,[...路径,k])返回 Object.fromEntries(many(t, n, []))}常量结果 =展平(数据,2)console.log(JSON.stringify(result, null, 2))

I would like to limit number of flattened structures inside an object. Consider example below.

Input:

const exampleObj = {
  foo: {
    bar: {
      biz: "hello"
    }
  }
};

Output:

{foo_bar_biz: "hello"}

I wanted to set a limiter (limit = 2) so that function will stop performing recursive function and return something like this

{foo_bar: "[Object] object"}

Here's a snippet:

const { useState, useEffect} = React;

const exampleObj = {
  foo: {
    bar: {
      biz: "hello"
    }
  }
};

let limit = 0;

function App() {
  const [state, setState] = useState({});

  useEffect(() => {
    flatten(exampleObj);
  }, []);

  const flatten = (data, parent, result = {}) => {
    for (let key in data) {
      const propName = parent ? parent + "_" + key : key;
      if (typeof data[key] === "object") {
        limit++;
        if (limit <= 1) {
          flatten(data[key], propName, result);
        } else {
          setState(prevState => {
            return {
              ...prevState,
              [propName]:
                typeof data[key] === "object" ? "[Object] object" : data[key]
            };
          });
        }
      } else {
        result[propName] = data[key];
        setState({
          ...state,
          [propName]: data[key]
        });
      }
    }
  };

  console.log(state);

  return (
    <div>
      <p>Start editing to see some magic happen :)</p>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>

<div id="root"></div>

I've prepared a solution for that, but it is quite cumbersome. https://stackblitz.com/edit/react-u5klvc

解决方案

Here's one possible implementation of flatten. Notice how it's completely decoupled from React or a specific React component. It works on any JavaScript objects -

const snakecase = s =>
  s.join("_")
  
const flatten = (t = {}, n = Infinity, join = snakecase) =>
{ const many = (t, n, path) =>
    n >= 0 && Object(t) === t
      ? Object.entries(t).flatMap(_ => one(_, n - 1, path))
      : [ [ join(path), t ] ]
      
  const one = ([ k, v ], n, path) =>
    many(v, n, [...path, k])
  
  return Object.fromEntries(many(t, n, []))
}

Given some example data -

const data =
  { a1: 11
  , a2: { b1: 21, b2: 22 }
  , a3: { b1: { c1: 311, c2: 312 }
        , b2: { c1: 321, c2: 322, c3: { d1: 3231 } }
        }
  }

A depth of 1 flattens one level -

flatten(data, 1)

{
  "a1": 11,
  "a2_b1": 21,
  "a2_b2": 22,
  "a3_b1": {
    "c1": 311,
    "c2": 312
  },
  "a3_b2": {
    "c1": 321,
    "c2": 322,
    "c3": {
      "d1": 3231
    }
  }
}

A depth of 2 flattens two levels -

flatten(data, 2) // => ...

{
  "a1": 11,
  "a2_b1": 21,
  "a2_b2": 22,
  "a3_b1_c1": 311,
  "a3_b1_c2": 312,
  "a3_b2_c1": 321,
  "a3_b2_c2": 322,
  "a3_b2_c3": {
    "d1": 3231
  }
}

The default depth is inifinity -

flatten(data) // => ...

{
  "a1": 11,
  "a2_b1": 21,
  "a2_b2": 22,
  "a3_b1_c1": 311,
  "a3_b1_c2": 312,
  "a3_b2_c1": 321,
  "a3_b2_c2": 322,
  "a3_b2_c3_d1": 3231
}

The default join is snakecase, but the parameter can be specified at the call site -

const camelCase = ([ first = "", ...rest ]) =>
  first + rest.map(upperFirst).join("")

const upperFirst = ([ first = "", ...rest ]) =>
  first.toUpperCase() + rest.join("")

flatten(data, 2, camelCase) // => ...

{
  "a1": 11,
  "a2B1": 21,
  "a2B2": 22,
  "a3B1C1": 311,
  "a3B1C2": 312,
  "a3B2C1": 321,
  "a3B2C2": 322,
  "a3B2C3": {
    "d1": 3231
  }
}

Expand the snippet below to verify the results in your own browser -

const data =
  { a1: 11
  , a2: { b1: 21, b2: 22 }
  , a3: { b1: { c1: 311, c2: 312 }
        , b2: { c1: 321, c2: 322, c3: { d1: 3231 } }
        }
  }
  
const snakecase = s =>
  s.join("_")
  
const flatten = (t = {}, n = Infinity, join = snakecase) =>
{ const many = (t, n, path) =>
    n >= 0 && Object(t) === t
      ? Object.entries(t).flatMap(_ => one(_, n - 1, path))
      : [ [ join(path), t ] ]
      
  const one = ([ k, v ], n, path) =>
    many(v, n, [...path, k])
  
  return Object.fromEntries(many(t, n, []))
}

const result =
  flatten(data, 2)

console.log(JSON.stringify(result, null, 2))

这篇关于展平对象和限制嵌套数量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆