我正在寻找一种有效的方法来在数组内的对象中返回唯一值。例如下一个对象:
{
"products": [{
"id": 1,
"category": "test1",
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"category": "test2",
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"category": "test1",
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"category": "test2",
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
}
我想返回的是以下内容:
{"option": [ "A", "B", "C" ] },{"type": ["A", "B", "C"] }
所以我要为标签对象内的每个项目创建一个新对象。之后,我想要一个在所有产品上都具有唯一值的数组。
我在另一个功能上做了一些相同的事情:
Array.from(new Set(data.map(p => { return p.category; })))
这是一个较高的级别,可以更轻松地进行。有人可以将我推向正确的方向吗?
答案 0 :(得分:6)
改为设置两组,一组用于到目前为止找到的option
,而另一组用于到目前为止找到的type
:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
const options = new Set();
const types = new Set();
for (const { tags: { option=[], type=[] } } of obj.products) {
for (const o of option) options.add(o);
for (const t of type) types.add(t);
}
console.log({
option: [...options],
type: [...types]
});
另一种选择,用于任意键:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
const setObj = {};
for (const { tags } of obj.products) {
for (const [key, arr] of Object.entries(tags)) {
if (!setObj[key]) setObj[key] = new Set();
for (const item of arr) setObj[key].add(item);
}
}
const output = Object.fromEntries(
Object.entries(setObj).map(([key, set]) => [key, [...set]])
);
console.log(output);
答案 1 :(得分:3)
function getUnique(array, keys) {
var maps = new Map(keys.map(k => [k, new Set]));
array.forEach(({ tags }) =>
keys.forEach(k => (tags[k] || []).forEach(v => maps.get(k).add(v))));
return Array.from(maps, ([k, s]) => ({ [k]: Array.from(s) }));
}
var data = { products: [{ id: 1, tags: { option: ["A", "B"] } }, { id: 2, tags: { option: ["B"], type: ["A", "B", "C"] } }, { id: 3, tags: { type: ["A"] } }, { id: 4, tags: { option: ["B", "C"], type: ["A", "C"] } }] },
unique = getUnique(data.products, ['option', 'type']);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
答案 2 :(得分:3)
您可以使用两个必需的键创建一个对象,然后将其设置为空数组。然后遍历数组并将新元素添加到该数组中,然后删除重复项
const arr = [{
"id": 1,
"tags": {
"option": ["A", "B"]
}}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
} }, {
"id": 3,
"tags": {
"type": ["A"]
}}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}}]
const object = {option:[] , type: []}
arr.forEach(({tags}) => {
for(let prop in object){
if(tags[prop]){
object[prop] = [...new Set([...object[prop], ...tags[prop]])]
}
}
})
console.log(object)
答案 3 :(得分:3)
您可以使用Array.prototype.reduce()来使结果变量{ option: [], type: [] }
['option', 'type']
代码:
const data = {"products": [{"id": 1,"tags": {"option": ["A", "B"]}}, {"id": 2,"tags": {"option": ["B"],"type": ["A", "B", "C"]}}, {"id": 3,"tags": {"type": ["A"]}}, {"id": 4,"tags": {"option": ["B", "C"],"type": ["A", "C"]}}]}
const result = data.products.reduce((a, { tags }) => {
['option', 'type'].forEach(prop => {
a[prop] = [...new Set(a[prop].concat(tags[prop] || []))]
})
return a
}, { option: [], type: [] })
console.log(result)
答案 4 :(得分:3)
一个简单而有效的解决方案是:
const optionSet = new Set();
const typeSet = new Set();
data.products.forEach( pr =>{
if(pr.tags.option){
pr.tags.option.forEach( op =>{
optionSet.add(op)
})
}
if(pr.tags.type){
pr.tags.type.forEach( tp =>{
typeSet.add(tp);
})
}
})
性能比较:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
//efficient solution
let t0 = performance.now();
const optionSet = new Set();
const typeSet = new Set();
obj.products.forEach( pr =>{
if(pr.tags.option){
pr.tags.option.forEach( op =>{
optionSet.add(op)
})
}
if(pr.tags.type){
pr.tags.type.forEach( tp =>{
typeSet.add(tp);
})
}
})
let s1Result = {
options: [...optionSet],
types: [...typeSet]
}
let t1 = performance.now();
let s1Runtime = t1-t0
console.log("efficient took: ",s1Runtime);
//accepted answer
let t2 = performance.now();
const setObj = {};
for (const { tags } of obj.products) {
for (const [key, arr] of Object.entries(tags)) {
if (!setObj[key]) setObj[key] = new Set();
for (const item of arr) setObj[key].add(item);
}
}
const s2Result = Object.fromEntries(
Object.entries(setObj).map(([key, set]) => [key, [...set]])
);
let t3 = performance.now();
let s2Runtime = t3-t2
console.log("current solution took: ",s2Runtime);
//runtime comparison
console.log("efficient solution is "+ ((s1Runtime)/(s2Runtime)).toFixed(2)*100 + " % faster current solution");
console.log("efficient solution result:", s1Result);
console.log("current solution result:", s2Result);