【问题标题】:Group Multiple Objects Based on Type Using lodash使用 lodash 根据类型对多个对象进行分组
【发布时间】:2019-10-07 19:59:00
【问题描述】:

我想将unordered-list-itemordered-list-item 分组。

下面是原结构:

{
  data: {
    areas: [{
      sections: [{
        rjf: [
          {
            type: "unordered-list-item",
            text: "Item 1",
          },
          {
            type: "unordered-list-item",
            text: "Item 2",
          },
          {
            type: "paragraph",
            text: "This is text",
          }]
      }]
    }]
  }
}

现在我想将所有列表项组合成一个新对象。

所以预期的结构是:

{
  data: {
    areas: [{
      sections: [{
        rjf: [
          {
            type: "list",
            items: [{
              type: "unordered-list-item",
              text: "Item 1",
            },
            {
              type: "unordered-list-item",
              text: "Item 2",
            }]
          },
          {
            type: "paragraph",
            text: "This is text",
          }]
      }]
    }]
  }
}

所以我想将所有 unordered-list-item and ordered-list-item 移动到 items 数组和下面的对象 typeparagraph 不应该受到影响。

我在 TypeScript 中创建了一个解决方案,但是代码太长了:

const areas = data.areas;
      const listItemTypes = ['unordered-list-item', 'ordered-list-item'];
      return areas.map(area => {
        return area.sections.map(section => {
          let lastHeadingIndex = -1;
          return section.rjf.reduce((acc, current, index) => {
            if (!current.type || !listItemTypes.includes(current.type)) {
              lastHeadingIndex = acc.length;
              return [...acc, current];
            }
            let listObject = acc.find((el, i) => i > lastHeadingIndex && i < index && el.type === 'list');
            if (!listObject) {
              listObject = {
                type: 'list',
                items: [current]
              };
              return [...acc, listObject];
            }
            listObject.items = [...listObject.items, current];
            return acc;
          }, []);
        });
      });

如何使用 lodash 实现相同的功能?

****更新****

我尝试使用 lodash,但似乎不起作用。

var content = {
  data: {
    areas: [{
      sections: [{
        rjf: [{
            type: "unordered-list-item",
            text: "Item 1",
          },
          {
            type: "unordered-list-item",
            text: "Item 2",
          },
          {
            type: "paragraph",
            text: "This is text",
          }
        ]
      }]
    }]
  }
};

var result = content.data.areas.map((area => {
    return area.sections.map(section => {
       section.rfj = _.groupBy(section.rfj, 'type');
    });
}));

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, '  ') + '</pre>';
&lt;script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"&gt;&lt;/script&gt;

【问题讨论】:

  • 你可以改变输入还是想要一个新对象?
  • 我想要一个新对象

标签: javascript arrays typescript lodash


【解决方案1】:

您可以使用另一种方法,通过复制每个对象 leven 并映射所有数组并使用分组函数对最后一层进行分组。

这种方法使用 am iter 函数来获取每个级别和起始对象的所有函数。

最后,它返回一个具有给定结构和分组项的新对象。

function copy(source, fn) {
    return Object.assign({}, ...Object
        .entries(source)
        .map(([k, v]) => ({ [k]: fn(v) }))
    );
}

function map(array, fn) {
    return array.map(fn);
}

function group(array) {
    var items;
    return array.reduce((r, o) => {
        if (listItemTypes.includes(o.type)) {
            if (!items) {
                items = [];
                r.push({ type: 'list', items });
            }
            items.push(o);
        } else {
            items = undefined;
            r.push(o);
        }
        return r;
    }, []);
}

function iter([fn, ...fns], object) {
    return fn ? fn(object, iter.bind(null, fns)) : object;
}    

var object = { data: { areas: [{ sections: [{ rjf: [{ type: "unordered-list-item", text: "Item 1" }, { type: "unordered-list-item", text: "Item 2" }, { type: "paragraph", text: "This is text" }] }] }] } },
    listItemTypes = ['unordered-list-item', 'ordered-list-item'],
    result = iter([copy, copy, map, copy, map, copy, group], object);

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

【讨论】:

    【解决方案2】:

    你可以把你的代码简化成这样。

    • areassections 上使用嵌套的map
    • 您将返回来自map 的数组。返回具有sectionsrjf 属性的对象(假设两个结构都是只有一个属性的对象)
    • 循环通过rjf 时,创建2 个数组:itemsothers
    • 根据types数组includes是否是当前对象的type,将每个对象分组到这2个数组中。
    • 使用一个 list 对象 ({ type: "list", items }) 和 others 数组中的剩余对象创建一个数组

    const types = ['unordered-list-item', 'ordered-list-item'],
          input = {data:{areas:[{sections:[{rjf:[{type:"unordered-list-item",text:"Item 1",},{type:"unordered-list-item",text:"Item 2",},{type:"paragraph",text:"This is text",}]}]}]}}
    
    const areas = input.data.areas.map(a => {
      return {
        sections: a.sections.map(s => {
          const items = [], others = [];
          
          s.rjf.forEach(o =>
            types.includes(o.type) ? items.push(o) : others.push(o)
          )
    
          return { rjf: [{ type: "list", items }, ...others] }
        })
      }
    })
    
    console.log({ data: { areas } })
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      【解决方案3】:
      return data.areas.map((area => {
          return area.sections.map(section => {
             return section.rfj = _.groupBy(section.rfj, 'type')
          })
      })
      

      如果您需要更具体的结构,您可能需要对结果进行一些微调,但这应该可以完成大部分工作

      【讨论】:

      • 是的data.开头是错误的。应该是content.data.areas(...
      猜你喜欢
      • 2016-12-27
      • 2021-05-04
      • 2018-08-28
      • 1970-01-01
      • 2018-01-09
      • 2019-08-31
      • 1970-01-01
      • 2018-11-03
      • 1970-01-01
      相关资源
      最近更新 更多