Группировка нескольких объектов на основе типа с использованием lodash - PullRequest
2 голосов
/ 21 мая 2019

Я хочу сгруппировать unordered-list-item и ordered-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, и следующий объект type, такой как paragraph, не должен подвергаться воздействию.

Я создал решение в 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?

**** UPDATE ****

Я пытался с 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 = '' + JSON.stringify(result, null, '  ') + '
;
<script src="https://cdn.jsdelivr.net/lodash/4.17.2/lodash.min.js"></script>

Ответы [ 3 ]

0 голосов
/ 21 мая 2019

Вы можете упростить свой код до чего-то вроде этого.

  • Используйте вложенные map для areas и sections.
  • Вы возвращаете массивы из обоих map.Вместо этого возвращайте объекты со свойствами sections и rjf (при условии, что обе структуры являются объектами только с одним свойством)
  • При циклическом просмотре rjf создайте 2 массива: items и others
  • Сгруппируйте каждый объект в эти 2 массива в зависимости от того, является ли types массив includes текущим объектом type.
  • Создание массива с одним 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; }
0 голосов
/ 21 мая 2019

Вы могли бы использовать другой подход, скопировав каждый объект 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; }
0 голосов
/ 21 мая 2019
return data.areas.map((area => {
    return area.sections.map(section => {
       return section.rfj = _.groupBy(section.rfj, 'type')
    })
})

Возможно, вам понадобится немного доработать результат, если вам нужна более конкретная структура, но это должно сделать большую часть работы

...