【问题标题】:Creating a new object using reduce in JS在 JS 中使用 reduce 创建一个新对象
【发布时间】:2021-06-07 08:18:35
【问题描述】:

我一直在处理使用 reduce 从嵌套数组创建对象。 该对象需要具有 initialValue 值的 _iud 键,来自包含这两个键的对象。我创建了一个可以遍历它们但不能返回具有我获得的所有新属性的新对象的函数。我尝试使用浅拷贝和深拷贝来克隆 acc 但无法成功:( 谁能帮我一把?

这是嵌套数组

export const formData = [
  {
component: 'page',
label: 'Page 1',
_uid: '0c946643-5a83-4545-baea-055b27b51e8a',
fields: [
  {
    component: 'field_group',
    label: 'Name',
    _uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
    fields: [
      {
        component: 'text',
        label: 'First Name',
        initialValue: '2345432',
        type: 'text',
        _uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
      },
      {
        component: 'text',
        label: 'Last Name',
        initialValue: '2345432',
        type: 'text',
        _uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
      },
    ],
  },
  {
    component: 'text',
    label: 'Email',
    initialValue: '2345432',
    type: 'email',
    _uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
  },
  {
    component: 'text',
    label: 'Phone',
    initialValue: '2345432',
    type: 'text',
    _uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
  },
],
  },
  {
component: 'page',
label: 'Page 2',
_uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
fields: [
  {
    component: 'options',
    label: 'Radio Buttons',
    type: 'radio',
    initialValue: '2345432',
    _uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
    options: [
      {
        component: 'option',
        label: 'Option 1',
        value: 'one',
      },
      {
        component: 'option',
        label: 'Option 2',
        value: 'two',
      },
    ],
  },
  {
    component: 'text',
    label: 'Conditional Field',
    type: 'text',
    _uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
    initialValue: '2345432',
    conditional: {
      value: 'two',
      field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
    },
  },
],
  },
  {
component: 'page',
label: 'Page 3a',
_uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
initialValue: '2345432',
conditional: {
  value: 'one',
  field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
  {
    component: 'options',
    label: 'More radio buttons',
    type: 'radio',
    _uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
    initialValue: '2345432',
    options: [
      { component: 'option', label: 'Option 1', value: 'one' },
      { component: 'option', label: 'Option 2', value: 'two' },
    ],
  },
],
  },
  {
component: 'page',
label: 'Page 3b',
_uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
conditional: {
  value: 'two',
  initialValue: '2345432',
  field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
  {
    component: 'options',
    label: 'Something to toggle',
    type: 'radio',
    _uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
    options: [
      {
        component: 'option',
        label: 'Option 1',
        value: 'one',
      },
      { component: 'option', label: 'Option 2', value: 'two' },
    ],
  },
  {
    component: 'field_group',
    label: 'Name',
    _uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
    fields: [
      {
        component: 'text',
        label: 'First Name',
        initialValue: '2345432',
        type: 'text',
        _uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
      },
      {
        component: 'text',
        label: 'Last Name',
        initialValue: '2345432',
        type: 'text',
        _uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
      },
    ],
  },
  {
    component: 'text',
    label: 'Email',
    initialValue: '2345432',
    type: 'email',
    _uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
  },
  {
    component: 'text',
    label: 'Phone',
    initialValue: '2345432',
    type: 'text',
    _uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
  },
],
  },
  {
component: 'page',
label: 'Page 4',
_uid: '0c946643-5a83-4545-baea-065b27b51e8a',
fields: [
  {
    component: 'text',
    label: 'Final Comment',
    initialValue: '2345432',
    type: 'text',
    _uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
  },
],
  },
]

功能:

 function getInitialValues(formData = []) {
    return Array.from(formData).reduce((acc, currentValue, idx) => {
      const arrayOfStrings = ['page', 'field_group', 'options']
      const str = currentValue.component
      const found = arrayOfStrings.find((v) => str === v)
      if (found) {
        // console.log('entro', currentValue)
        getInitialValues(currentValue?.fields)

        return acc
      }

      if (
        (currentValue.component === 'text' || currentValue.component === 'select') &&
        currentValue.label === 'Conditional Field'
      ) {
        acc[currentValue._uid] = currentValue?.initialValue

        return acc
      }
      return acc
    }, {})
  }

我的预期结果是来自所有具有 initialValues 的 _uids 的类似结果(仅供参考)

{
5b9b79d2-32f2-42a1-b89f-203dfc0b6b98: '2345432',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b97: '2345431',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b96: '2345430',

}

【问题讨论】:

    标签: javascript arrays


    【解决方案1】:

    我发现将_uid/initialValue 属性的提取与这些属性的格式分离到输出对象中更容易。

    这是一个递归 extract 函数和一个基于它的简单 convert 函数。

    const extract = (xs) =>
      xs .flatMap (({initialValue, _uid, fields = []}) =>
        [[_uid, initialValue], ...extract (fields)]
      ) .filter (([_, init]) => init != null)
    
    const convert = xs =>
      Object .fromEntries (extract (xs))
    
    const formData = [{component: "page", label: "Page 1", _uid: "0c946643-5a83-4545-baea-055b27b51e8a", fields: [{component: "field_group", label: "Name", _uid: "eb169f76-4cd9-4513-b673-87c5c7d27e02", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "5b9b79d2-32f2-42a1-b89f-203dfc0b6b98"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "6eff3638-80a7-4427-b07b-4c1be1c6b186"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "f61233e8-565e-43d0-9c14-7d7f220c6020"}]}, {component: "page", label: "Page 2", _uid: "3a30803f-135f-442c-ab6e-d44d7d7a5164", fields: [{component: "options", label: "Radio Buttons", type: "radio", initialValue: "2345432", _uid: "bd90f44a-d479-49ae-ad66-c2c475dca66b", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "text", label: "Conditional Field", type: "text", _uid: "bd90f44a-d479-49ae-ad66-c2c475daa66b", initialValue: "2345432", conditional: {value: "two", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}}]}, {component: "page", label: "Page 3a", _uid: "cd392929-c62e-4cdb-b4dd-914035c1cc8d", initialValue: "2345432", conditional: {value: "one", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "More radio buttons", type: "radio", _uid: "a15bef56-ab67-4b98-a781-4441cc3bba56", initialValue: "2345432", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}]}, {component: "page", label: "Page 3b", _uid: "1dd4ec7c-fb53-47f4-af1b-1ab8f805b888", conditional: {value: "two", initialValue: "2345432", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "Something to toggle", type: "radio", _uid: "3ca9237d-e225-4950-a298-f81ce996cb85", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "field_group", label: "Name", _uid: "b8406cb5-ff0d-4a83-a8f8-99740b6d91f7", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "c6e065e1-dbcb-44ea-831f-ac3af889e964"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "e279ba9c-3c9b-4df8-b267-d14b3c2adcdd"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "a95208a0-7673-48a8-b704-2fb408fa6eec"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "8dde5083-0619-42d6-8fc7-0563c35d03ad"}]}, {component: "page", label: "Page 4", _uid: "0c946643-5a83-4545-baea-065b27b51e8a", fields: [{component: "text", label: "Final Comment", initialValue: "2345432", type: "text", _uid: "f61231e8-565e-43d0-9c14-7d7f220c6020"}]}]
    
    console .log (convert (formData))

    .as-console-wrapper {max-height: 100% !important; top: 0}

    这个问题似乎还暗示您想要更新数据。我认为这是一个单独的步骤,您似乎已经能够做到。

    【讨论】:

      【解决方案2】:

      问题出在:

       if (found) {
          // console.log('entro', currentValue)
          getInitialValues(currentValue?.fields)
      
          return acc
        }
      

      这个对getInitialValues 的调用应该返回一个没有保存到acc 的结果。

      纠正它的一种方法是执行以下操作:

          if (found) {
              const res = getInitialValues(currentValue.fields);
              return Object.assign(acc, res);
          }
      

      可能还有其他问题,但这是为我站起来的问题。

      注意:“预期结果”中三分之二的uid没有出现在第一个代码sn-p中(formData的例子)。 至于另一个(使用 uid:5b9b79d2-32f2-42a1-b89f-203dfc0b6b98),它的 label'First Name' 而不是 'Conditional Field' - 这就是它没有出现在输出中的原因。

      (完整)更正的代码

      function getInitialValues (formData = []) {
          return formData.reduce((acc, currentValue) => {
              const arrayOfStrings = ['page', 'field_group', 'options'];
              const str = currentValue.component;
              const found = arrayOfStrings.find((v) => str === v);
              if (found) {
                  const res = getInitialValues(currentValue.fields);
                  return Object.assign(acc, res);
              }
      
              if (
                  (currentValue.component === 'text' || currentValue.component === 'select') &&
                  currentValue.label === 'Conditional Field'
              ) {
                  if (currentValue.initialValue) {
                      acc[currentValue._uid] = currentValue.initialValue;
                  }
              }
              return acc;
          }, {});
      

      【讨论】:

        【解决方案3】:

        我发现了一个简单的forEach 循环,递归更简单。

        const formData = [{
            component: 'page',
            label: 'Page 1',
            _uid: '0c946643-5a83-4545-baea-055b27b51e8a',
            fields: [{
                component: 'field_group',
                label: 'Name',
                _uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
                fields: [{
                    component: 'text',
                    label: 'First Name',
                    initialValue: '2345432',
                    type: 'text',
                    _uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
                  },
                  {
                    component: 'text',
                    label: 'Last Name',
                    initialValue: '2345432',
                    type: 'text',
                    _uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
                  },
                ],
              },
              {
                component: 'text',
                label: 'Email',
                initialValue: '2345432',
                type: 'email',
                _uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
              },
              {
                component: 'text',
                label: 'Phone',
                initialValue: '2345432',
                type: 'text',
                _uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
              },
            ],
          },
          {
            component: 'page',
            label: 'Page 2',
            _uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
            fields: [{
                component: 'options',
                label: 'Radio Buttons',
                type: 'radio',
                initialValue: '2345432',
                _uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
                options: [{
                    component: 'option',
                    label: 'Option 1',
                    value: 'one',
                  },
                  {
                    component: 'option',
                    label: 'Option 2',
                    value: 'two',
                  },
                ],
              },
              {
                component: 'text',
                label: 'Conditional Field',
                type: 'text',
                _uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
                initialValue: '2345432',
                conditional: {
                  value: 'two',
                  field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
                },
              },
            ],
          },
          {
            component: 'page',
            label: 'Page 3a',
            _uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
            initialValue: '2345432',
            conditional: {
              value: 'one',
              field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
            },
            fields: [{
              component: 'options',
              label: 'More radio buttons',
              type: 'radio',
              _uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
              initialValue: '2345432',
              options: [{
                  component: 'option',
                  label: 'Option 1',
                  value: 'one'
                },
                {
                  component: 'option',
                  label: 'Option 2',
                  value: 'two'
                },
              ],
            }, ],
          },
          {
            component: 'page',
            label: 'Page 3b',
            _uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
            conditional: {
              value: 'two',
              initialValue: '2345432',
              field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
            },
            fields: [{
                component: 'options',
                label: 'Something to toggle',
                type: 'radio',
                _uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
                options: [{
                    component: 'option',
                    label: 'Option 1',
                    value: 'one',
                  },
                  {
                    component: 'option',
                    label: 'Option 2',
                    value: 'two'
                  },
                ],
              },
              {
                component: 'field_group',
                label: 'Name',
                _uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
                fields: [{
                    component: 'text',
                    label: 'First Name',
                    initialValue: '2345432',
                    type: 'text',
                    _uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
                  },
                  {
                    component: 'text',
                    label: 'Last Name',
                    initialValue: '2345432',
                    type: 'text',
                    _uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
                  },
                ],
              },
              {
                component: 'text',
                label: 'Email',
                initialValue: '2345432',
                type: 'email',
                _uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
              },
              {
                component: 'text',
                label: 'Phone',
                initialValue: '2345432',
                type: 'text',
                _uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
              },
            ],
          },
          {
            component: 'page',
            label: 'Page 4',
            _uid: '0c946643-5a83-4545-baea-065b27b51e8a',
            fields: [{
              component: 'text',
              label: 'Final Comment',
              initialValue: '2345432',
              type: 'text',
              _uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
            }, ],
          },
        ]
        
        function getInitialValues(formData = [], output=[]) {
          formData.forEach(obj => {
            // first check for the Conditional Field label
            let found = obj.hasOwnProperty('label') && obj.label === "Conditional Field";
            // then loop through the component fields if neccesary
            if (!found) ['select','text','options'].forEach(val => {
            if (obj.hasOwnProperty('component') && obj.component === val) found = true;})
            // if found update the output array
            if (found) output.push({[obj._uid]: obj.initialValue})
            // check for recursion
            if (obj.hasOwnProperty('fields')) output = getInitialValues(obj.fields, output)
          })
          return output;
        }
        
        console.log(getInitialValues(formData))

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-06-30
          • 1970-01-01
          • 2021-12-14
          • 1970-01-01
          • 2018-03-26
          • 1970-01-01
          相关资源
          最近更新 更多