theprogrammablemind
Version:
129 lines (115 loc) • 3.04 kB
JavaScript
const _ = require('lodash')
const deepEqual = require('deep-equal')
const groupBy = (property, list) => {
const groups = {}
for (const element of list) {
if (!groups[element[property]]) {
groups[element[property]] = []
}
groups[element[property]].push(element)
}
return groups
}
const toList = (value) => {
if (value.marker === 'list') {
return value
} else {
return {
marker: 'list',
types: Array.from(new Set((value.types || []).concat(['list', value.marker]))),
value: [value]
}
}
}
const concatLists = (l1, l2) => {
l1 = toList(l1)
l2 = toList(l2)
return {
marker: 'list',
types: Array.from(new Set(l1.types.concat(l2.types))),
value: Array.from(new Set(l1.value.concat(l2.value)))
}
}
const findPropertyWithManyValues = (contexts, properties) => {
for (const property of properties) {
if (new Set(contexts.map((context) => context[property])).size == 1) {
return property
}
}
}
/*
class JSONSet {
constructor(list = []) {
this.members = []
for (const element of list) {
this.add(element)
}
}
toList(element) {
return this.list
}
add(element) {
if (!this.has(element)) {
this.list.push(element)
}
}
has(searchFor) {
for (const element of this.list) {
if (!deepEqual(searchFor, element) {
return true
}
}
return false
}
}
*/
// x want y and z OR A
// x and y want z B
// x wants and likes y C
const canonicalDefault = (value) => {
if (!value || !value.marker) {
return value
}
return { marker: value.marker, value: value.value, word: value.wordi, types: value.types }
}
// if properties null then check the contexts for unflatten property
const unflatten = (contexts, properties, canonical = canonicalDefault) => {
const grouped = {}
for (const context of contexts) {
if (!grouped[context.marker]) {
grouped[context.marker] = []
}
grouped[context.marker].push(context)
}
let results = []
for (const key in grouped) {
results = results.concat(unflattenHelper(grouped[key], properties || grouped[key][0].unflatten, canonical))
}
return results
}
// properties -> order of preference for grouping values, for example B,A,c
const unflattenHelper = (contexts, properties, canonical) => {
if (contexts.length < 2) {
return contexts
}
if (!properties) {
return contexts
}
const groupedByMarker = groupBy('marker', contexts)
const unflats = []
for (const key in groupedByMarker) {
const grouping = groupedByMarker[key]
const groupingProp = findPropertyWithManyValues(contexts, properties)
const first = _.cloneDeep(grouping[0])
for (const next of grouping.slice(1)) {
for (const prop in next) {
if (!deepEqual(canonical(next[prop]), canonical(first[prop]))) {
first[prop] = concatLists(first[prop], next[prop])
}
}
}
unflats.push(first)
}
return unflats
}
module.exports = { groupBy, unflatten }