Мне кажется, что вы хотите сделать три разные вещи. Вы хотите сгруппировать свои элементы по категориям. Вы хотите отсортировать категории так, чтобы те, у которых нет категории, были в самом конце, а те, у которых null
, были прямо перед этим. И вы хотите преобразовать свои элементы, сгруппировав категории в единые объекты, и оставив остальные разделенными.
Это делает несколько странное преобразование. Но это не так уж удивительно, так как и ваша структура ввода, и ваша структура вывода несколько странны.
Вот один из способов, который почти выполняет то, что вы спрашиваете:
const compare = ([a], [b]) =>
a == 'undefined' ? (b == 'undefined' ? '0' : 1) : b == 'undefined' ? -1
: a == 'null' ? (b == 'null' ? 0 : 1) : b == 'null' ? -1
: a < b ? -1 : a > b ? 1 : 0
const makeCat = ([key, nodes]) =>
key == 'null' || key == 'undefined'
? nodes .map (node => node .type)
: [{name: key, category: key, children: nodes .map (({type: {name}}) => ({name}))}]
const transform = pipe (
groupBy (prop ('categoryName')),
toPairs,
sort (compare),
chain (makeCat)
)
// changing this to demonstrate proper grouping.
// const testArray = [{id: 6, type: {name: "Test1", category: "Cat A"}, typeName: "Test1", categoryName: "Cat A"}, {id: 34, type: {name: "Test2", category: "Cat A"}, typeName: "Test2", categoryName: "Cat A"}, {id: 662, type: {name: "Test6", category: null}, typeName: "Test6", categoryName: null}, {id: 62, type: {name: "Test7", category: "Cat A"}, typeName: "Test7", categoryName: "Cat A"}, {id: 1190, type: {name: "Test8", category: null}, typeName: "Test8", categoryName: null}, {id: "other", type: {name: "Others", seen: true}, typeName: "Others"}];
const testArray = [{id: 662, type: {name: "Test6", category: null}, typeName: "Test6", categoryName: null}, {id: 6, type: {name: "Test1", category: "Cat A"}, typeName: "Test1", categoryName: "Cat A"}, {id: 34, type: {name: "Test2", category: "Cat A"}, typeName: "Test2", categoryName: "Cat A"}, {id: 62, type: {name: "Test7", category: "Cat A"}, typeName: "Test7", categoryName: "Cat A"}, {id: 1190, type: {name: "Test8", category: null}, typeName: "Test8", categoryName: null}, {id: "other", type: {name: "Others", seen: true}, typeName: "Others"}];
console .log (
transform (testArray)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {pipe, groupBy, prop, toPairs, sort, chain} = R </script>
compare
используется для сортировки. Он помещает undefined
категории в конец и null
категории непосредственно перед этим, сортируя остальные с естественной сортировкой. (Есть хороший аргумент, чтобы сделать более декларативную версию этого, но это отдельный вопрос, я думаю.)
makeCat
занимает имя категории и список узлов из исходного списка, а также создает и массив выходных узлов. Он обрабатывает дела null
/ undefined
отдельно от дел настоящей категории. Когда есть истинная категория, она создает массив, содержащий один элемент со свойствами name
, category
и children
. Если категория null
/ undefined
, мы просто извлекаем свойство type
из каждого дочернего элемента и возвращаем их массив. Вот что вы можете изменить, если у вас не работает немного другой вывод.
transform
сначала сворачивает все это вместе в конвейер группирование по элементам по их свойству categoryName
, затем преобразование полученного объекта в массив из пар key
- value
, сортировка результата по compare
, а затем вызов chain
(аналогично Array.prototype.flatMap
в в этом случае) с makeCat
в результирующем массиве.
Единственное отличие в поведении, которое я отмечаю из вашего обновленного запроса на вывод, заключается в том, что он включает свойство seen
в последнем узле. Это потому, что мы просто повторно используем элемент type
. Если вам нужен какой-то другой процесс, вы можете просто заменить node => node .type
на что-то более подходящее.