Я большой поклонник библиотеки функционального программирования Рамда .(Отказ от ответственности: я один из его авторов.) Я склонен мыслить в терминах простых, многократно используемых функций.
Когда я думаю о том, как решить эту проблему, я думаю об этом с точки зрения Рамды.И я бы, вероятно, решил эту проблему следующим образом:
const {pipe, groupBy, prop, map, sortBy, values, head, unnest} = R;
const transform = pipe(
groupBy(prop('id')),
map(sortBy(prop('num'))),
values,
sortBy(pipe(head, prop('num'))),
unnest
)
const data = [{"id": "ABC", "num": 111}, {"id": "DEF", "num": 130}, {"id": "XYZ", "num": 115}, {"id": "QRS", "num": 98}, {"id": "DEF", "num": 119}, {"id": "ABC", "num": 137}, {"id": "LMN", "num": 122}, {"id": "ABC", "num": 108}]
console.log(transform(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
Я думаю, что это достаточно читабельно, по крайней мере, когда вы поймете, что канал создает конвейер функций, каждый из которых передает свой результат следующему.
Теперь часто нет причин включать большую библиотеку, такую как Ramda, для решения довольно простой задачи.Но все функции, используемые в этой версии, легко можно использовать повторно.Поэтому имеет смысл попытаться создать свои собственные версии этих функций и сделать их доступными для остальной части вашего приложения.Фактически, именно так создаются библиотеки, такие как Ramda.
Итак, вот версия, которая имеет простые реализации этих функций, которые вы можете поместить в служебную библиотеку:
const groupBy = (fn) => (arr) => arr.reduce((acc, val) => (((acc[fn(val)] || (acc[fn(val)] = [])).push(val)), acc), {})
const head = (arr) => arr[0]
const mapObj = (fn) => (obj) => Object.keys(obj).reduce((acc, val) => (acc[val] = fn(obj[val]), acc), {})
const pipe = (...fns) => (arg) => fns.reduce((a, f) => f(a), arg)
const prop = (name) => (obj) => obj[name]
const values = Object.values
const unnest = (arr) => [].concat(...arr)
const sortBy = (fn) => (arr) => arr.slice(0).sort((a, b) => {
const aa = fn(a), bb = fn(b)
return aa < bb ? -1 : aa > bb ? 1 : 0
})
const transform = pipe(
groupBy(prop('id')),
mapObj(sortBy(prop('num'))),
values,
sortBy(pipe(head, prop('num'))),
unnest
)
const data = [{"id": "ABC", "num": 111}, {"id": "DEF", "num": 130}, {"id": "XYZ", "num": 115}, {"id": "QRS", "num": 98}, {"id": "DEF", "num": 119}, {"id": "ABC", "num": 137}, {"id": "LMN", "num": 122}, {"id": "ABC", "num": 108}]
console.log(transform(data))