根据布尔值 属性 减少 JavaScript 对象数组
Reduce JavaScrip Array of Objects based on boolean property value
我正在尝试将视频信息中的以下数据减少到自定义对象结构中,该结构删除了“标签”键重复项,但也保留了所有遇到的可用功能。
初始数据如下所示:
[
{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": false
}
}
]
如您所见,单个分辨率标签有很多对象,但其中一些具有 HDR,而另一些具有 60fps,而其他可能具有 none 个或两者。
我想做的是使用以下 reduce 函数来减少这个数组。
假设resolutions
就是上面的Object:
resolutions.reduce((unique, o) => {
if (!unique.some((obj) => obj.label === o.label)) {
unique.push(o);
}
return unique;
}, []);
这给了我以下结构:
[
{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
}
]
但是如果你仔细观察,你会发现在 reduce 操作期间,一些布尔值与每个唯一标签键的第一个元素值合并,我最终需要启用真正的功能,即使只是其中一个他们是真的。
2160p
标签是一个很好的例子,实际上有一个对象有 HDR: true
但最后我只是把它当作 false
你知道如何用现代 JavaScript 来处理这种情况吗?
如果您首先使用 .reduce
按 label
分组并在每次迭代中进行分组会更容易:
- 如果
label
不在 acc
中,添加第一个对象(当前项目)
- 否则,以一种方式更新存储类别的功能,如果其功能之一不可用而该类别中的新当前项目具有该功能,则将其设置为
true
最后,return具有合并特征的对象分组列表:
const resolutions = [
{ "label": "4320p", "features": { "HDR": false, "60fps": true } },
{ "label": "2160p", "features": { "HDR": false, "60fps": true } },
{ "label": "2160p", "features": { "HDR": true, "60fps": true } },
{ "label": "1440p", "features": { "HDR": false, "60fps": true } },
{ "label": "1440p", "features": { "HDR": true, "60fps": true } },
{ "label": "1080p", "features": { "HDR": false, "60fps": true } },
{ "label": "1080p", "features": { "HDR": true, "60fps": true } },
{ "label": "1080p", "features": { "HDR": false, "60fps": true } },
{ "label": "1080p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": true } },
{ "label": "720p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": false } },
{ "label": "720p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": true, "60fps": true } },
{ "label": "480p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": true, "60fps": false } },
{ "label": "360p", "features": { "HDR": true, "60fps": true } },
{ "label": "360p", "features": { "HDR": false, "60fps": false } },
{ "label": "360p", "features": { "HDR": false, "60fps": false } },
{ "label": "360p", "features": { "HDR": true, "60fps": false } },
{ "label": "240p", "features": { "HDR": true, "60fps": true } },
{ "label": "240p", "features": { "HDR": false, "60fps": false } },
{ "label": "240p", "features": { "HDR": false, "60fps": false } },
{ "label": "240p", "features": { "HDR": true, "60fps": false } },
{ "label": "144p", "features": { "HDR": true, "60fps": true } },
{ "label": "144p", "features": { "HDR": false, "60fps": false } },
{ "label": "144p", "features": { "HDR": false, "60fps": false } },
{ "label": "144p", "features": { "HDR": true, "60fps": false } }
];
// update category's features if any is not available yet, and the new object has it
const _getUpdatedFeatures = (currentFeatures={}, newFeatures={}) => {
const updatedFeatures = {...currentFeatures};
for (let [feature, currentlyAvailable] of Object.entries(currentFeatures)) {
if(!currentlyAvailable && newFeatures[feature]===true) {
updatedFeatures[feature] = true;
}
}
return updatedFeatures;
}
// group by label and merge features availability
const res = Object.values(resolutions.reduce((acc, item) => {
const { label } = item;
const prev = acc[label];
if(!prev)
acc[label] = item;
else
acc[label] = { ...prev, features: _getUpdatedFeatures(prev.features, item.features) };
return acc;
}, {}));
console.log(res);
如果你想保持你的方法,你可以使用以下方法。您需要扩展 if
语句,以防您有偏好应保留哪个元素,以防有两个元素,一个将 HDR 设置为 true
,另一个将 60fps 设置为 true
(在这种情况下,使用此版本将选择发现的第一个分辨率):
const resolutions = [{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": false
}
}
]
const result = resolutions.reduce((unique, o) => {
const uniqueResolution = unique.find((resolution) => resolution.label === o.label)
if (!uniqueResolution) {
return unique.concat(o)
} else if (uniqueResolution.features.HDR && uniqueResolution.features['60fps']) {
return unique
} else if (o.features.HDR && o.features['60fps']) {
// swap element since there is a better one
return unique.map((resolution) => {
if (resolution.label === o.label) return o
return resolution
})
}
return unique
}, [])
console.log(result)
我正在尝试将视频信息中的以下数据减少到自定义对象结构中,该结构删除了“标签”键重复项,但也保留了所有遇到的可用功能。
初始数据如下所示:
[
{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": false
}
}
]
如您所见,单个分辨率标签有很多对象,但其中一些具有 HDR,而另一些具有 60fps,而其他可能具有 none 个或两者。
我想做的是使用以下 reduce 函数来减少这个数组。
假设resolutions
就是上面的Object:
resolutions.reduce((unique, o) => {
if (!unique.some((obj) => obj.label === o.label)) {
unique.push(o);
}
return unique;
}, []);
这给了我以下结构:
[
{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
}
]
但是如果你仔细观察,你会发现在 reduce 操作期间,一些布尔值与每个唯一标签键的第一个元素值合并,我最终需要启用真正的功能,即使只是其中一个他们是真的。
2160p
标签是一个很好的例子,实际上有一个对象有 HDR: true
但最后我只是把它当作 false
你知道如何用现代 JavaScript 来处理这种情况吗?
如果您首先使用 .reduce
按 label
分组并在每次迭代中进行分组会更容易:
- 如果
label
不在acc
中,添加第一个对象(当前项目) - 否则,以一种方式更新存储类别的功能,如果其功能之一不可用而该类别中的新当前项目具有该功能,则将其设置为
true
最后,return具有合并特征的对象分组列表:
const resolutions = [
{ "label": "4320p", "features": { "HDR": false, "60fps": true } },
{ "label": "2160p", "features": { "HDR": false, "60fps": true } },
{ "label": "2160p", "features": { "HDR": true, "60fps": true } },
{ "label": "1440p", "features": { "HDR": false, "60fps": true } },
{ "label": "1440p", "features": { "HDR": true, "60fps": true } },
{ "label": "1080p", "features": { "HDR": false, "60fps": true } },
{ "label": "1080p", "features": { "HDR": true, "60fps": true } },
{ "label": "1080p", "features": { "HDR": false, "60fps": true } },
{ "label": "1080p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": true } },
{ "label": "720p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": false } },
{ "label": "720p", "features": { "HDR": true, "60fps": true } },
{ "label": "720p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": true, "60fps": true } },
{ "label": "480p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": false, "60fps": false } },
{ "label": "480p", "features": { "HDR": true, "60fps": false } },
{ "label": "360p", "features": { "HDR": true, "60fps": true } },
{ "label": "360p", "features": { "HDR": false, "60fps": false } },
{ "label": "360p", "features": { "HDR": false, "60fps": false } },
{ "label": "360p", "features": { "HDR": true, "60fps": false } },
{ "label": "240p", "features": { "HDR": true, "60fps": true } },
{ "label": "240p", "features": { "HDR": false, "60fps": false } },
{ "label": "240p", "features": { "HDR": false, "60fps": false } },
{ "label": "240p", "features": { "HDR": true, "60fps": false } },
{ "label": "144p", "features": { "HDR": true, "60fps": true } },
{ "label": "144p", "features": { "HDR": false, "60fps": false } },
{ "label": "144p", "features": { "HDR": false, "60fps": false } },
{ "label": "144p", "features": { "HDR": true, "60fps": false } }
];
// update category's features if any is not available yet, and the new object has it
const _getUpdatedFeatures = (currentFeatures={}, newFeatures={}) => {
const updatedFeatures = {...currentFeatures};
for (let [feature, currentlyAvailable] of Object.entries(currentFeatures)) {
if(!currentlyAvailable && newFeatures[feature]===true) {
updatedFeatures[feature] = true;
}
}
return updatedFeatures;
}
// group by label and merge features availability
const res = Object.values(resolutions.reduce((acc, item) => {
const { label } = item;
const prev = acc[label];
if(!prev)
acc[label] = item;
else
acc[label] = { ...prev, features: _getUpdatedFeatures(prev.features, item.features) };
return acc;
}, {}));
console.log(res);
如果你想保持你的方法,你可以使用以下方法。您需要扩展 if
语句,以防您有偏好应保留哪个元素,以防有两个元素,一个将 HDR 设置为 true
,另一个将 60fps 设置为 true
(在这种情况下,使用此版本将选择发现的第一个分辨率):
const resolutions = [{
"label": "4320p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "2160p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1440p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "1080p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "720p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "720p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "480p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "360p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "240p",
"features": {
"HDR": true,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": true
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": false,
"60fps": false
}
},
{
"label": "144p",
"features": {
"HDR": true,
"60fps": false
}
}
]
const result = resolutions.reduce((unique, o) => {
const uniqueResolution = unique.find((resolution) => resolution.label === o.label)
if (!uniqueResolution) {
return unique.concat(o)
} else if (uniqueResolution.features.HDR && uniqueResolution.features['60fps']) {
return unique
} else if (o.features.HDR && o.features['60fps']) {
// swap element since there is a better one
return unique.map((resolution) => {
if (resolution.label === o.label) return o
return resolution
})
}
return unique
}, [])
console.log(result)