[英]filter an array of objects based on an object with an array as it's property value in react
[英]Filter and de dupe Javascript Objects based on it's property value
根据“Platform”和“Title”,我需要对下面的object进行de dupe,得到最早的“DateFirstSeen”和最新的“DateLastSeen”。
输入 Object:
[
{
"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"
},
{
"Platform": "Netflix",
"DateFirstSeen": {
"Day": "20",
"Month": "08",
"Year": "2014"
},
"DateLastSeen": {
"Day": "02",
"Month": "03",
"Year": "2020"
},
"Title": "Stranger Things"
},
{
"Platform": "Netflix",
"DateFirstSeen": {
"Month": "08",
"Year": "2014"
},
"DateLastSeen": {
"Month": "10",
"Year": "2017"
},
"Title": "Stranger Things"
},
{
"Platform": "Netflix",
"DateFirstSeen": {
"Month": "12",
"Year": "2012"
},
"DateLastSeen": {
"Day": "05",
"Month": "01",
"Year": "2017"
},
"Title": "Stranger Things"
},
{
"Platform": "Hulu",
"DateFirstSeen": {
"Month": "05",
"Year": "2010"
},
"DateLastSeen": {
"Month": "12",
"Year": "2016"
},
"Title": "Watchmen"
},
{
"Platform": "Netflix",
"DateFirstSeen": {
"Day": "03",
"Month": "04",
"Year": "2015"
},
"DateLastSeen": {
"Day": "03",
"Month": "04",
"Year": "2015"
},
"Title": "Stranger Things"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "20",
"Month": "07",
"Year": "2005"
},
"DateLastSeen": {
"Month": "12",
"Year": "2012"
},
"Title": "See"
},
{
"Platform": "Hulu",
"DateFirstSeen": {
"Month": "01",
"Year": "2012"
},
"DateLastSeen": {
"Month": "01",
"Year": "2012"
},
"Title": "Watchmen"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Month": "09",
"Year": "2003"
},
"DateLastSeen": {
"Month": "02",
"Year": "2009"
},
"Title": "Snoopy Show"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "01",
"Month": "11",
"Year": "2008"
},
"DateLastSeen": {
"Day": "03",
"Month": "12",
"Year": "2008"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Month": "09",
"Year": "2008"
},
"DateLastSeen": {
"Month": "09",
"Year": "2008"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Month": "06",
"Year": "1999"
},
"DateLastSeen": {
"Day": "31",
"Month": "08",
"Year": "2006"
},
"Title": "Snoopy Show"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "12",
"Month": "08",
"Year": "2006"
},
"DateLastSeen": {
"Day": "12",
"Month": "08",
"Year": "2006"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "18",
"Month": "06",
"Year": "2006"
},
"DateLastSeen": {
"Day": "18",
"Month": "06",
"Year": "2006"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Month": "08",
"Year": "2005"
},
"DateLastSeen": {
"Month": "08",
"Year": "2005"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "20",
"Month": "07",
"Year": "2005"
},
"DateLastSeen": {
"Day": "20",
"Month": "07",
"Year": "2005"
},
"Title": "See"
}
]
所需的 output 是:
[
{
"Platform": "Disney",
"DateFirstSeen": {
"Day": "15",
"Month": "06",
"Year": "2019"
},
"DateLastSeen": {
"Day": "08",
"Month": "02",
"Year": "2021"
},
"Title": "Jojo Rabbit"
},
{
"Platform": "Netflix",
"DateFirstSeen": {
"Month": "12",
"Year": "2012"
},
"DateLastSeen": {
"Month": "11",
"Year": "2020"
},
"Title": "Stranger Things"
},
{
"Platform": "Hulu",
"DateFirstSeen": {
"Month": "05",
"Year": "2010"
},
"DateLastSeen": {
"Month": "12",
"Year": "2016"
},
"Title": "Watchmen"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Day": "20",
"Month": "07",
"Year": "2005"
},
"DateLastSeen": {
"Month": "12",
"Year": "2012"
},
"Title": "See"
},
{
"Platform": "AppleTV",
"DateFirstSeen": {
"Month": "06",
"Year": "1999"
},
"DateLastSeen": {
"Month": "02",
"Year": "2009"
},
"Title": "Snoopy Show"
}
]
我曾尝试使用下划线来获取所有唯一对象_.uniq
,但这只会给我平台和标题的唯一值,但错过了 DateFirstSeen 和 DateLastSeen。
我想确保这些字段在过滤过程中不会丢失。
使用以下助手 function,
function dayNumber(dateObj) {
var day = _.get(dateObj, 'Day', 1),
month = _.get(dateObj, 'Month'),
year = _.get(dateObj, 'Year');
return year * 372 + month * 31 + +day;
}
以下表达式将计算所需的 output:
_.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) {
我们首先编写一个 function ,它接受一个日期 object 例如{ "Day": "20", "Month": "07", "Year": "2005" }
并返回一个数字。 我们需要它以便能够应用_.min
和_.max
,它们可以分别计算集合的最小值和最大值。
var day = _.get(dateObj, 'Day', 1),
在dayNumber
function 中,我们继续从dateObj
中取出零件。 _.get
function 让我们指定一个后备值(在本例中为1
),这很方便,因为并非所有日期对象都有Day
属性。
month = _.get(dateObj, 'Month'),
year = _.get(dateObj, 'Year');
return year * 372 + month * 31 + +day;
}
通过这些部分,我们计算了自西历开始以来的天数的近似值。 该值显然不准确,因为我们假设每个月有 31 天,但它仍然会正确获取日期的相对顺序。 请注意,我们使用符号+day
来强制Day
属性为数字。 年份和月份是由我们将它们乘以一个数字的事实来强制的。
有了dayNumber
function,我们可以继续讨论大表达式。
_.chain(data)
我们使用_.chain
以便我们可以连续应用几个 Underscore 函数,每个函数都对前面的 Underscore function 的结果进行操作。 我们将在表达式的其余部分中再看到几次。
.groupBy('Platform')
仍然在第一行,我们首先按Platform
属性对数据进行分组。 这将创建一个 object,其中每个键是一个平台名称,对应的值是来自该平台的数据的子集:
{
Disney: [...],
Netflix: [...],
Hulu: [...],
AppleTV: [...]
}
这个中间结果立即链接到下一个下划线 function:
.map(function(platformData, platform) {
对于每一对平台名称及其对应的数据,我们将计算某种结果,然后将所有结果返回到一个数组中(参见_.map
)。 在下一行,我们发现自己在 function 中,它将计算一个这样的结果。
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);
我们终于开始工作了,首先,我们从titleData
中提取所有DateFirstSeen
属性,然后我们使用_.min
和我们的dayNumber
助手 function 取最早的属性。 同样,我们使用_.max
DateLastSeen
return {
Platform: platform,
Title: title,
DateFirstSeen: firstSeen.value(),
DateLastSeen: lastSeen.value()
};
我们已经完成了关于这个单一标题的所有信息,因此我们将数据重新组合成一个新的 object。 我们使用_().value
将结果从我们的链中取出。
}).value();
我们关闭计算单个标题结果的 function 以及对_.map
的调用,我们将这个 function 传递给它。 我们也结束了为整个平台计算结果的链并获取它的.value()
。 这是一个标题对象数组。
}).flatten().value();
最后,我们关闭整个表达式。 我们插入对_.flatten
的调用,因为否则我们将拥有一个 arrays 数组,而不仅仅是一个平面数组。
注意:如果我们保证每个标题只出现在一个平台上,我们可以跳过按平台分组,最后不需要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,
Title: title,
DateFirstSeen: firstSeen.value(),
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" }, { "Platform": "Netflix", "DateFirstSeen": { "Day": "20", "Month": "08", "Year": "2014" }, "DateLastSeen": { "Day": "02", "Month": "03", "Year": "2020" }, "Title": "Stranger Things" }, { "Platform": "Netflix", "DateFirstSeen": { "Month": "08", "Year": "2014" }, "DateLastSeen": { "Month": "10", "Year": "2017" }, "Title": "Stranger Things" }, { "Platform": "Netflix", "DateFirstSeen": { "Month": "12", "Year": "2012" }, "DateLastSeen": { "Day": "05", "Month": "01", "Year": "2017" }, "Title": "Stranger Things" }, { "Platform": "Hulu", "DateFirstSeen": { "Month": "05", "Year": "2010" }, "DateLastSeen": { "Month": "12", "Year": "2016" }, "Title": "Watchmen" }, { "Platform": "Netflix", "DateFirstSeen": { "Day": "03", "Month": "04", "Year": "2015" }, "DateLastSeen": { "Day": "03", "Month": "04", "Year": "2015" }, "Title": "Stranger Things" }, { "Platform": "AppleTV", "DateFirstSeen": { "Day": "20", "Month": "07", "Year": "2005" }, "DateLastSeen": { "Month": "12", "Year": "2012" }, "Title": "See" }, { "Platform": "Hulu", "DateFirstSeen": { "Month": "01", "Year": "2012" }, "DateLastSeen": { "Month": "01", "Year": "2012" }, "Title": "Watchmen" }, { "Platform": "AppleTV", "DateFirstSeen": { "Month": "09", "Year": "2003" }, "DateLastSeen": { "Month": "02", "Year": "2009" }, "Title": "Snoopy Show" }, { "Platform": "AppleTV", "DateFirstSeen": { "Day": "01", "Month": "11", "Year": "2008" }, "DateLastSeen": { "Day": "03", "Month": "12", "Year": "2008" }, "Title": "See" }, { "Platform": "AppleTV", "DateFirstSeen": { "Month": "09", "Year": "2008" }, "DateLastSeen": { "Month": "09", "Year": "2008" }, "Title": "See" }, { "Platform": "AppleTV", "DateFirstSeen": { "Month": "06", "Year": "1999" }, "DateLastSeen": { "Day": "31", "Month": "08", "Year": "2006" }, "Title": "Snoopy Show" }, { "Platform": "AppleTV", "DateFirstSeen": { "Day": "12", "Month": "08", "Year": "2006" }, "DateLastSeen": { "Day": "12", "Month": "08", "Year": "2006" }, "Title": "See" }, { "Platform": "AppleTV", "DateFirstSeen": { "Day": "18", "Month": "06", "Year": "2006" }, "DateLastSeen": { "Day": "18", "Month": "06", "Year": "2006" }, "Title": "See" }, { "Platform": "AppleTV", "DateFirstSeen": { "Month": "08", "Year": "2005" }, "DateLastSeen": { "Month": "08", "Year": "2005" }, "Title": "See" }, { "Platform": "AppleTV", "DateFirstSeen": { "Day": "20", "Month": "07", "Year": "2005" }, "DateLastSeen": { "Day": "20", "Month": "07", "Year": "2005" }, "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);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.