基于布尔属性值减少 JavaScrip 对象数组

时间:2021-01-30 18:39:00

标签: javascript object boolean reduce

我正在尝试将视频信息中的以下数据减少到自定义对象结构中,该结构删除“标签”键重复项,但同时保留所有遇到的可用功能。

初始数据如下所示:

[
  {
    "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,而其他可能没有它们或两者都具有。

我想要做的是使用以下 reduce 函数来减少这个数组。 假设 resolutions 是上述对象:

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 管理这种情况有任何想法吗?

2 个答案:

答案 0 :(得分:1)

如果您首先使用 label 并在每次迭代中按 .reduce 分组会更容易:

  • 如果 label 不在 acc 中,添加第一个对象(当前项)
  • 否则,以某种方式更新存储类别的功能,如果其中一个功能不可用而此类别中的新当前项目具有该功能,则将其设置为 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 } }
];

// 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);

答案 1 :(得分:1)

如果你想保持你的方法,你可以使用以下方法。您需要扩展 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)