简体   繁体   English

如何基于对象中的属性合并对象数组中的对象

[英]How to merge objects in an array of objects, based on a property in the objects

I have an array of activities like 我有一系列活动,例如

this.activities = [
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: disregard,
timestamp: 14356787
},
{
id: 54,
event_type: 'NA',
user_id: 56,
user_name: 'Anand',
purpose: 'privacy',
timestamp: ''
},
{
id: 54,
event_type: 'FA',
user_id: 56,
user_name: 'Anand',
purpose: 'Call',
timestamp: ''
},
{
id: 54,
event_type: 'FA',
user_id: 56,
user_name: 'Anand',
purpose: 'Listen',
timestamp: ''
},
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: 'Not allowed',
timestamp: 14356784
},
{
id: 54,
event_type: 'NA',
user_id: 56,
user_name: 'Anand',
purpose: 'data',
timestamp: 14356786
},
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: 'voicemail',
timestamp: 14356785
},
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: 'phone',
timestamp: 14356775
},
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: 'email',
timestamp: 14356776
},
{
id: 54,
event_type: 'CA',
user_id: 56,
user_name: 'Anand',
purpose: 'letter',
timestamp: 14356777
}
]

I want to group/filter this array by the event_type 'CA' only, based on a 5ms timestamp difference for each activity. 我只想根据每个活动的5 毫秒时间戳差异,按event_type'CA'对该数组进行分组/过滤。 So if timestamp of the activity with event_type 'CA' falls within 5ms of each other, then club those activities and form a new activity with everything same except a new event_type for the clubbed activities called CA_combined. 因此,如果具有event_type'CA '的活动的时间戳落在彼此的5毫秒之内,则将这些活动合并,并形成一个具有相同内容的新活动,但对于称为CA_combined的合并活动的新event_type除外。 So this array should like this 所以这个数组应该像这样

this.activities = [
{
id: 54,
event_type: 'CA_combined',
user_id: 56,
user_name: 'Anand',
purposes: ['disregard', 'Not allowed', 'voicemail'],
timestamp: 14356787
},
{
id: 54,
event_type: 'CA_combined',
user_id: 56,
user_name: 'Anand',
purposes: ['letter','email','phone']
timestamp: 14356777
},
{
id: 54,
event_type: 'NA',
user_id: 56,
user_name: 'Anand',
purpose: 'privacy',
timestamp: ''
},
{
id: 54,
event_type: 'FA',
user_id: 56,
user_name: 'Anand',
purpose: 'Call',
timestamp: ''
},
{
id: 54,
event_type: 'FA',
user_id: 56,
user_name: 'Anand',
purpose: 'Listen',
timestamp: ''
},
{
id: 54,
event_type: 'NA',
user_id: 56,
user_name: 'Anand',
purpose: 'data',
timestamp: 14356786
}
]

How do I go about achieving something like this? 我该如何实现这样的目标? My try as of now, filter all of them whose event_type is CA and sort the array based on the timestamp value 到目前为止,我尝试过滤所有event_type为CA的消息,并根据时间戳值对数组进行排序

let consentActivities = this.activities.filter(c => {
        if (c.event_type === 'CA') {
          return true
        } else {
          return false
        }
      })
consentActivities.sort((a, b) => {
        return b.timestamp - a.timestamp
      })

This is where I dont know how to group activities within a 5ms and completely losing it 这是我不知道如何在5毫秒内将活动分组并完全丢失的地方

 if (consentActivities.length && consentActivities[0].timestamp - consentActivities[consentActivities.length - 1].timestamp <= 5) {
        consentActivities[0].purposes = []
        consentActivities.forEach((p) => {
          consentActivities[0].purposes.push(p.purpose)
        })
        // consentActivities.splice(1, consentActivities.length)
      }

Any inputs are highly appreciated 任何输入都受到高度赞赏

You already made the right first steps: Filter out CAs, sort, then you can easily group by accessing the previous index: 您已经完成了正确的第一步:筛选出CA,进行排序,然后可以通过访问上一个索引轻松地进行分组:

  const entries = data
    .filter(it => it.event_type === "CA")
    .sort((a, b) => a.timestamp - b.timestamp);

 const grouped = [];

 for(const entry of entries) {
   const previous = grouped[grouped.length - 1];
   if(previous && Math.abs(entry.timestamp - previous.timestamp) < 5) {
      previous.purposes.push(entry.purpose);
   } else {
     grouped.push({ id: entry.id, /*...*/, purposes: [entry.purpose] });
   }
}

Settled on this O(n) solution 着眼于这个O(n)解决方案

 sortedCAarray.forEach((act, index) => {
        const currActivityTime = moment(act.timestamp).valueOf()
        console.log(currActivityTime)
        //  First element is already added, avoid duplicates
        if (index < 1) return
        // Grab the last key from the timestampMap
        const timestampKeys = Object.keys(timestampMap)
        const key = timestampKeys[timestampKeys.length - 1]
        // Add the activity and purpose to the respective arrays and set for that key if the key is within 5 units of the current activity timestamp
        if (Math.abs(key - currActivityTime) < 5) {
          let activities = timestampMap[key].activities
          let purposes = timestampMap[key].purposes
          activities.push(act)
          purposes.add(act.purpose)
          let timestamp = moment(activities[activities.length - 1].timestamp).valueOf()
          // Edge case to to include all activities in the same bucket if they were within 5 ms of any element within the bucket
          if (timestamp > key) {
            Object.defineProperty(timestampMap, timestamp,
              Object.getOwnPropertyDescriptor(timestampMap, key))
            delete timestampMap[key]
          }
        } else {
          // If not just create a new key with the current activity timestamp as the key
          timestampMap[currActivityTime] = { activities: [act], purposes: new Set([act.purpose]) }
        }
      })

Would appreciate any improvements to this! 希望对此有所改善! Thank you 谢谢

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM