如何解决根据其属性值过滤和删除 Javascript 对象
根据“平台”和“标题”,我需要去重复下面的对象,得到最早的“DateFirstSeen”和最新的“DateLastSeen”。
输入对象:
[
{
"Platform": "disney","DateFirstSeen": {
"Day": "15","Month": "06","Year": "2019"
},"DateLastSeen": {
"Day": "08","Month": "02","Year": "2021"
},"Title": "Jojo Rabbit"
},{
"Platform": "Netflix","DateFirstSeen": {
"Month": "08","Year": "2014"
},"DateLastSeen": {
"Month": "11","Year": "2020"
},"Title": "Stranger Things"
},"DateFirstSeen": {
"Day": "20","Month": "08","DateLastSeen": {
"Day": "02","Month": "03","DateLastSeen": {
"Month": "10","Year": "2017"
},"DateFirstSeen": {
"Month": "12","Year": "2012"
},"DateLastSeen": {
"Day": "05","Month": "01",{
"Platform": "Hulu","DateFirstSeen": {
"Month": "05","Year": "2010"
},"DateLastSeen": {
"Month": "12","Year": "2016"
},"Title": "Watchmen"
},"DateFirstSeen": {
"Day": "03","Month": "04","Year": "2015"
},"DateLastSeen": {
"Day": "03",{
"Platform": "AppleTV","Month": "07","Year": "2005"
},"Title": "See"
},"DateFirstSeen": {
"Month": "01","DateLastSeen": {
"Month": "01","DateFirstSeen": {
"Month": "09","Year": "2003"
},"DateLastSeen": {
"Month": "02","Year": "2009"
},"Title": "Snoopy Show"
},"DateFirstSeen": {
"Day": "01","Month": "11","Year": "2008"
},"Month": "12","DateLastSeen": {
"Month": "09","DateFirstSeen": {
"Month": "06","Year": "1999"
},"DateLastSeen": {
"Day": "31","Year": "2006"
},"DateFirstSeen": {
"Day": "12","DateLastSeen": {
"Day": "12","DateFirstSeen": {
"Day": "18","DateLastSeen": {
"Day": "18","DateLastSeen": {
"Month": "08","DateLastSeen": {
"Day": "20","Title": "See"
}
]
所需的输出是:
[
{
"Platform": "disney","Title": "Snoopy Show"
}
]
我曾尝试使用下划线来获取所有唯一对象 _.uniq
但这仅给了我平台和标题的唯一值但错过了 DateFirstSeen 和 DateLastSeen。
我想确保这些字段不会在过滤过程中丢失。
解决方法
使用以下辅助函数,
function dayNumber(dateObj) {
var day = _.get(dateObj,'Day',1),month = _.get(dateObj,'Month'),year = _.get(dateObj,'Year');
return year * 372 + month * 31 + +day;
}
以下表达式将计算所需的输出:
_.chain(data).groupBy('Platform').map(function(platformData,platform) {
return _.chain(platformData).groupBy('Title').map(function(titleData,title) {
var titleChain = _.chain(titleData),firstSeen = titleChain.map('DateFirstSeen').min(dayNumber),lastSeen = titleChain.map('DateLastSeen').max(dayNumber);
return {
Platform: platform,Title: title,DateFirstSeen: firstSeen.value(),DateLastSeen: lastSeen.value()
};
}).value();
}).flatten().value();
让我们把它拆开。
function dayNumber(dateObj) {
我们首先编写一个函数,该函数接受一个日期对象(例如 { "Day": "20","Month": "07","Year": "2005" }
)并返回一个数字。我们需要它以便能够应用 _.min
和 _.max
,它们可以分别计算集合的最小值和最大值。
var day = _.get(dateObj,
在 dayNumber
函数中,我们继续从 dateObj
中取出部分。 _.get
函数让我们可以指定回退值(在本例中为 1
),这很方便,因为并非所有日期对象都具有 Day
属性。
month = _.get(dateObj,'Year');
return year * 372 + month * 31 + +day;
}
通过这些部分,我们计算了自西历开始以来的近似天数。该值显然不准确,因为我们假设每个月都有 31 天,但它仍然会得到日期的相对顺序。请注意,我们使用符号 +day
将 Day
属性强制为数字。年和月被我们乘以一个数字这一事实所强制。
使用 dayNumber
函数后,我们可以继续进行大表达式。
_.chain(data)
我们使用 _.chain
以便我们可以连续应用多个 Underscore 函数,每个函数都对前一个 Underscore 函数的结果进行操作。我们将在表达式的其余部分中多次看到这一点。
.groupBy('Platform')
仍然在第一行,我们首先按 Platform
属性对数据进行分组。这将创建一个对象,其中每个键是一个平台名称,对应的值是来自该平台的数据的子集:
{
Disney: [...],Netflix: [...],Hulu: [...],AppleTV: [...]
}
这个中间结果会立即链接到下一个 Underscore 函数中:
.map(function(platformData,platform) {
对于每一对平台名称及其对应的数据,我们将计算某种结果,然后将所有结果返回到一个数组中(参见_.map
)。在下一行,我们发现自己在计算一个这样的结果的函数中。
return _.chain(platformData).groupBy('Title').map(function(titleData,title) {
这一行看起来与前一行惊人地相似。我们只对单个平台的数据进行分组,而不是所有数据,并按标题分组。前面有一个return
语句,表示这条链的最终结果也是整个平台的计算结果。
var titleChain = _.chain(titleData),
我们为单个标题的数据子集制作了另一个链。我们为这条链命名 (titleChain
),因为我们将使用它两次。
firstSeen = titleChain.map('DateFirstSeen').min(dayNumber),lastSeen = titleChain.map('DateLastSeen').max(dayNumber);
我们终于开始营业了!首先,我们从 DateFirstSeen
中提取所有 titleData
属性,然后使用 _.min
和我们的 dayNumber
辅助函数获取最早的属性。同样,我们使用 DateLastSeen
找到最新的 _.max
。
return {
Platform: platform,DateLastSeen: lastSeen.value()
};
我们拥有关于这个单一标题的所有信息,因此我们将数据重新组合成一个新对象。我们使用 _().value
从我们的链中取出结果。
}).value();
我们关闭计算单个标题结果的函数以及我们传递此函数的对 _.map
的调用。我们也结束计算整个平台结果的链并取其 .value()
。这是一个标题对象数组。
}).flatten().value();
最后,我们关闭整个表达式。我们插入对 _.flatten
的调用,否则我们将拥有一个数组数组,而不仅仅是一个平面数组。
注意:如果我们保证每个标题只出现在一个平台上,我们就可以跳过按平台分组,最后就不需要 flatten
。在这种情况下,代码更简单,速度也更快:
_.chain(data).groupBy('Title').map(function(titleData,title) {
var titleChain = _.chain(titleData),firstSeen = titleChain.map('DateFirstSeen').min(formatAsDate),lastSeen = titleChain.map('DateLastSeen').max(formatAsDate);
return {
Platform: _.first(titleData).Platform,DateLastSeen: lastSeen.value()
};
}).value();
由于我们不再按平台分组,我们不再需要关闭 platform
参数,因此我们使用 _.first
获取平台名称。通常,您不能假设数组有第一个元素(因为数组可能为空),但这里是安全的,因为 groupBy
永远不会产生空组。
这个更简单的表达式恰好适用于您的示例数据,但通常假设每个标题对于单个平台都是唯一的可能并不安全。您的里程可能会有所不同。
, const data = [
{
"Platform": "Disney","DateFirstSeen": {
"Day": "15","Month": "06","Year": "2019"
},"DateLastSeen": {
"Day": "08","Month": "02","Year": "2021"
},"Title": "Jojo Rabbit"
},{
"Platform": "Netflix","DateFirstSeen": {
"Month": "08","Year": "2014"
},"DateLastSeen": {
"Month": "11","Year": "2020"
},"Title": "Stranger Things"
},"DateFirstSeen": {
"Day": "20","Month": "08","DateLastSeen": {
"Day": "02","Month": "03","DateLastSeen": {
"Month": "10","Year": "2017"
},"DateFirstSeen": {
"Month": "12","Year": "2012"
},"DateLastSeen": {
"Day": "05","Month": "01",{
"Platform": "Hulu","DateFirstSeen": {
"Month": "05","Year": "2010"
},"DateLastSeen": {
"Month": "12","Year": "2016"
},"Title": "Watchmen"
},"DateFirstSeen": {
"Day": "03","Month": "04","Year": "2015"
},"DateLastSeen": {
"Day": "03",{
"Platform": "AppleTV","Year": "2005"
},"Title": "See"
},"DateFirstSeen": {
"Month": "01","DateLastSeen": {
"Month": "01","DateFirstSeen": {
"Month": "09","Year": "2003"
},"DateLastSeen": {
"Month": "02","Year": "2009"
},"Title": "Snoopy Show"
},"DateFirstSeen": {
"Day": "01","Month": "11","Year": "2008"
},"Month": "12","DateLastSeen": {
"Month": "09","DateFirstSeen": {
"Month": "06","Year": "1999"
},"DateLastSeen": {
"Day": "31","Year": "2006"
},"DateFirstSeen": {
"Day": "12","DateLastSeen": {
"Day": "12","DateFirstSeen": {
"Day": "18","DateLastSeen": {
"Day": "18","DateLastSeen": {
"Month": "08","DateLastSeen": {
"Day": "20","Title": "See"
}
];
const result = data.reduce((a,it)=>{
const index = a.map(i=>i.Title).indexOf(it.Title);
if(index===-1){
a.push(it);
}else{
if(a[index].DateLastSeen.Year < it.DateLastSeen.Year || a[index].DateLastSeen.Month < it.DateLastSeen.Month){
a[index].DateLastSeen = it.DateLastSeen;
}
}
return a;
},[])
console.log(result);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。