请注意,取值范和entry4分担property: 'subject'
和property: 'field'
相同的值。
进出口寻找一个表演性和清洁的方式来过滤这个数组,并得到共享双方value
s那些property
ies的条目。
更新:
我并不想转换成数据,但分析它。所以从分析中返回的值应该是这样的:
[['entry1', 'entry4'],...]
而这种分析列表,我可以轻松地将我triples = [...]
到三倍的名单,我删除条目之一(不事关它,可能是“取值范”或“entry4”),并更新另一个
[
{ subject: "entry1", property: "subject", value: "sport" },
{ subject: "entry1", property: "field", value: "category" },
{ subject: "entry1", property: "content", value: "football" },
{ subject: "entry1", property: "content", value: "basketball" },
]
array.filter(({property, value})=> property === 'sport' && value === 'category')
我不知道“运动”或“类别”。这些都是动态值。
代码片段:
const triples = [
{ subject: "entry1", property: "subject", value: "sport" },
{ subject: "entry1", property: "field", value: "category" },
{ subject: "entry1", property: "content", value: "football" },
{ subject: "entry4", property: "subject", value: "sport" },
{ subject: "entry4", property: "field", value: "category" },
{ subject: "entry4", property: "content", value: "basketball" },
{ subject: "entry2", property: "subject", value: "music" },
{ subject: "entry2", property: "field", value: "category" },
{ subject: "entry2", property: "content", value: "notes" },
{ subject: "entry3", property: "subject", value: "painting" },
{ subject: "entry3", property: "field", value: "category" },
{ subject: "entry3", property: "content", value: "drawings" }
];
我必须说,输入数据结构是不是最佳的,并且使用“主体”既是一个真正的对象属性和数值为property
将使它更加混乱。我会打电话给第一个概念(真正的subject
)“项”,因为采样值“取值范”,“ENTRY2”,...
这里有一个方法来提取["entry1", "entry4"]
为您的样品数据:
{
entry1: { subject: "sport", field: "category", content: "football" },
entry4: { subject: "sport", field: "category", content: "basketball" },
entry2: { subject: "music", field: "category", content: "notes" },
entry3: { subject: "painting", field: "category", content: "drawings" }
}
这将是更容易使用。下面的代码实际上将创建一个Map
,而不是一个普通的对象,但原理是一样的。group
属性。例如,上述的结果的第一个对象将与扩展:
group: '["sport","category"]'
{
'["sport","category"]': ["entry1","entry4"],
'["music","category"]': ["entry2"],
'["painting","category"]': ["entry3"]
}
下面是执行:
const triples = [{subject: "entry1", property: "subject", value: "sport"},{subject: "entry1", property: "field", value: "category"},{subject: "entry1", property: "content", value: "football"},{subject: "entry4", property: "subject", value: "sport"},{subject: "entry4", property: "field", value: "category"},{subject: "entry4", property: "content", value: "basketball"},{subject: "entry2", property: "subject", value: "music"},{subject: "entry2", property: "field", value: "category"},{subject: "entry2", property: "content", value: "notes"},{subject: "entry3", property: "subject", value: "painting"},{subject: "entry3", property: "field", value: "category"},{subject: "entry3", property: "content", value: "drawings"},];
// 1. Group the data by subject into objects where "property" and "value" are translated into key/value pairs:
const entries = new Map(triples.map(o => [o.subject, { entry: o.subject }]));
triples.forEach(o => entries.get(o.subject)[o.property] = o.value);
// 2. Define a group value for these objects (composed of subject and field)
entries.forEach(o => o.group = JSON.stringify([o.subject, o.field]));
// 3. Create Map of entries, keyed by their group value
const groups = new Map(Array.from(entries.values(), o => [o.group, []]));
entries.forEach(o => groups.get(o.group).push(o.entry));
// 4. Keep only the subarrays that have more than one value
const result = [...groups.values()].filter(group => group.length > 1);
console.log(result);
请注意,输出是一个嵌套的数组,因为在理论上可能有多种组合的条目,比如[ ["entry1", "entry4"], ["entry123", "entry521", "entry951"] ]
上述可以被修改/扩展以获得最终滤波结果。在第三步,你仍然会收集的对象(不只是入门值),然后将过滤结果被映射回原来的格式:
const triples = [{subject: "entry1", property: "subject", value: "sport"},{subject: "entry1", property: "field", value: "category"},{subject: "entry1", property: "content", value: "football"},{subject: "entry4", property: "subject", value: "sport"},{subject: "entry4", property: "field", value: "category"},{subject: "entry4", property: "content", value: "basketball"},{subject: "entry2", property: "subject", value: "music"},{subject: "entry2", property: "field", value: "category"},{subject: "entry2", property: "content", value: "notes"},{subject: "entry3", property: "subject", value: "painting"},{subject: "entry3", property: "field", value: "category"},{subject: "entry3", property: "content", value: "drawings"},];
// 1. Group the data by subject into objects where "property" and "value" are translated into key/value pairs:
const entries = new Map(triples.map(o => [o.subject, { entry: o.subject }]));
triples.forEach(o => entries.get(o.subject)[o.property] = o.value);
// 2. Define a group value for these objects (composed of subject and field)
entries.forEach(o => o.group = JSON.stringify([o.subject, o.field]));
// 3. Create Map of objects(*), keyed by their group value
const groups = new Map(Array.from(entries.values(), o => [o.group, []]));
entries.forEach(o => groups.get(o.group).push(o));
// 4. Keep only the subarrays that have more than one value
const result = [...groups.values()].filter(group => group.length > 1)
// 5. ...and convert it back to the original format:
.flatMap(group => [
{ subject: group[0].entry, property: "subject", value: group[0].subject },
{ subject: group[0].entry, property: "field", value: group[0].field },
...group.map(o => ({ subject: group[0].entry, property: "content", value: o.content }))
]);
console.log(result);
可以三元组的阵列减少到一个对象,其中result[propertyString][valueString]
与“属性”等于propertyString和“值”等于三元组的valueString的阵列:
triples.reduce((acc, triple) => {
acc[triple.property] = acc[triple.property] || {};
acc[triple.property][triple.value] = acc[triple.property][triple.value] || [];
acc[triple.property][triple.value].push(triple);
return acc;
}, {})
然后,您可以搜索你想要的属性和值对象,并检查是否有多于一个三。
我开始回答这个问题,但我们需要来回走,所以我可以更好地了解你在找什么。
let data = [
{subject: 'entry1', property: 'subject', value: 'sport'},
{subject: 'entry1', property: 'field', value: 'category'},
{subject: 'entry1', property: 'content', value: 'football'},
{ subject: 'entry4', property: 'subject', value: 'sport' },
{ subject: 'entry4', property: 'field', value: 'category' },
{ subject: 'entry4', property: 'content', value: 'basketball' },
{subject: 'entry2', property: 'subject', value: 'music'},
{subject: 'entry2', property: 'field', value: 'category'},
{subject: 'entry2', property: 'content', value: 'notes'},
{subject: 'entry3', property: 'subject', value: 'painting'},
{subject: 'entry3', property: 'field', value: 'category'},
{subject: 'entry3', property: 'content', value: 'drawing'}
]
let keys = data.map((item, inex) => { return item.subject })
let uniqueKeys = keys.filter((item, index) => { return keys.indexOf(item) >= index })
let propertiesWeCareAbout = ['subject', 'field']
let mappedValues = data.reduce((acc, item, index) => {
acc[item.subject] = {}
acc[item.subject].values = data.map((subItm, subIndx) => { if (item.subject === subItm.subject) { if (propertiesWeCareAbout.indexOf(subItm.property) > -1) {return subItm.value} }}).filter(Boolean)
return acc;
}, {})
// this is where I leave you... because I think you need to finish this up yourself.
// You have all the mapped data you need to solve your question.
// You now just need to map over the unique keys checking the `mappedValues` data structure for entries that have the same values in the values array.
// You can rename things if you want. But these are all the parts of the solution laid out.
// p.s. You can remove the 'category' string from the propertiesWeCareAbout array based on the example you provided... and you can simplify what I've provided in a number of ways.
// this is where you map to get just the strings of "entry1" and "entry4" based on the other mapped data provided. Then you can combine data as you said you need to.
let finalListOfEntriesThatNeedToBeMerged = uniqueKeys.map((item, index) => {return item})
console.log(mappedValues)
console.log(finalListOfEntriesThatNeedToBeMerged)
这就是你要开始。但接下来的步骤取决于您正在寻找的数据映射到什么。
我打算把重点放在未来此评论:“对于这些属性共享这两个值项”
使用lodash可以GROUPBY的subject
,由新subject
属性和field
财产转换为对象,GROUPBY对象,并将其转换回项目的数组:
const { flow, partialRight: pr, groupBy, map, set, head, flatMap, toPairs, isArray } = _;
const dontCollect = key => ['entry', 'subject', 'field'].includes(key);
const createPropery = (subject, property, value) => ({ subject, property, value });
const fn = flow(
pr(groupBy, 'subject'),
pr(map, (g, entry) => ({ // convert to object with the subject as entry
entry,
...g.reduce((r, o) => set(r, o.property, o.value), {}),
})),
pr(groupBy, o => `${o.subject}-${o.field}`),
pr(map, g => g.length > 1 ? _.mergeWith(...g, (a, b, k) => { // merge everything to an object
if(dontCollect(k)) return a;
return [].concat(a, b); // convert non entry, subject, or field properties to array if repeated
}) : head(g)),
pr(flatMap, ({ entry: subject, ...o }) => // convert back a series of rows
flow(
toPairs,
pr(flatMap, ([property, value]) => isArray(value) ?
map(value, v => createPropery(subject, property, v))
:
createPropery(subject, property, value)
)
)(o)
)
);
const triples = [{"subject":"entry1","property":"subject","value":"sport"},{"subject":"entry1","property":"field","value":"category"},{"subject":"entry1","property":"content","value":"football"},{"subject":"entry4","property":"subject","value":"sport"},{"subject":"entry4","property":"field","value":"category"},{"subject":"entry4","property":"content","value":"basketball"},{"subject":"entry2","property":"subject","value":"music"},{"subject":"entry2","property":"field","value":"category"},{"subject":"entry2","property":"content","value":"notes"},{"subject":"entry3","property":"subject","value":"painting"},{"subject":"entry3","property":"field","value":"category"},{"subject":"entry3","property":"content","value":"drawings"}];
const result = fn(triples);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
我首先筛选的所有property.subject
s并把它们还原成一个多维阵列中,其中每个阵列包含出现较然后一旦受试者值。
然后,我过滤所有property.field
s,并检查他们的property.subject
are相等。
然后,我创建一个映射对象(mergeEntriesBysubjectIndex
)从哪里获得{0: true, 1: false, 2: true}
每个按键对应subjects
索引值。
最后,我对mergeEntriesBysubjectIndex
运行,每个真正的指数将触发所有三元组基于索引subjects
新的合并项,新更新的阵列。
我的实现:
/*
* @description
* Get an mulitdimensional array, where each inner array represent a list
* of entries with similar value
*
* @ return [[], [], []]
*/
const subjects = Object.values(
triples
.filter(triple => triple.property === "subject")
.reduce((subjects, entry) => {
if (subjects[entry.value]) {
subjects[entry.value].push(entry.subject);
} else {
subjects[entry.value] = [];
subjects[entry.value].push(entry.subject);
}
return subjects;
}, {})
).filter(arr => arr.length > 1);
const fields = triples.filter(triple => triple.property === "field");
/*
* @description
* Create an object based on the "subjects" mulit-dimensional array from before
* Each key represent the index of "subjects", where the value is a boolean *
* representing a similar "property:field" value
*/
const mergeEntriesBysubjectIndex = subjects.reduce((filtered, chunk, index) => {
let values = [];
chunk.forEach(subject => {
const obj = fields.find(field => field.subject === subject).value;
values.push(obj);
});
filtered[index] = values.every((val, i, arr) => val === arr[0]);
return filtered;
}, {});
/*
* @description
* Get an array of subjects value (e.g. "entry1", "entry2")
* and return a new "merged" collection with uniqe objects
* and with the same name for a subject
*/
const mergeEntries = entries => {
const ent = triples.filter(triple => triple.subject === entries[0]);
const newContent = triples
.filter(
triple => triple.subject === entries[1] && triple.property === "content"
)
.map(triple => ({ ...triple, subject: entries[0] }));
return [...ent, ...newContent];
};
/*
* @description
* return a new updated list of triples without the specified entries
*/
const removeEntriesFromCurrentTriples = entries =>
triples.filter(triple => !entries.includes(triple.subject));
for (let index in mergeEntriesBysubjectIndex) {
if (mergeEntriesBysubjectIndex[index]) {
const mergeEntry = mergeEntries(subjects[index]);
const updateEntries = [
...removeEntriesFromCurrentTriples(subjects[index]),
...mergeEntry
];
// The new trasformed triples collection
console.log('transformed triples:', updateEntries)
}
}