重构 JSON 对象数组

Posted

技术标签:

【中文标题】重构 JSON 对象数组【英文标题】:Restructuring Array of JSON objects 【发布时间】:2020-09-12 16:10:00 【问题描述】:

我有一个 JSON 对象数组。但是,有些数据是重复的。有没有办法重组数组以排除重复值?我必须使用地图功能吗?还是 for 循环?

userData = [id:'101', Time:'3:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'6/25/20',
            id:'105', Time:'1:00pm', Date:'3/25/20',
            id:'105', Time:'5:00pm', Date:'5/25/20'
           ]

是否可以像这样重构数据?

userData = [ id:'101', Time:['3:00pm','5:00pm'], Date:['5/25/20', '6/25/20'],
             id:'105', Time:['1:00pm','5:00pm'], Date:['3/25/20','5/25/20']
           ]

如果您有任何指导或方向,将不胜感激! 谢谢!

【问题讨论】:

做一些研究以从数组生成一个 "groupBy" 对象 您真的要分别对TimeDate 进行分组和去重吗?根据我的经验,在大多数用例中,时间仅在某一天才有意义。 看起来它实际上会破坏数据,不是吗?没有日期上下文的去重复时间会被破坏吗? 感谢大家的回复。我很想显示所有时间和日期,无论它们是否对应。只要他们不重复。再次感谢您的帮助。 【参考方案1】:
let userData = [id:'101', Time:'3:00pm', Date:'5/25/20',
        id:'101', Time:'5:00pm', Date:'5/25/20',
        id:'101', Time:'5:00pm', Date:'6/25/20',
        id:'105', Time:'1:00pm', Date:'3/25/20',
        id:'105', Time:'5:00pm', Date:'5/25/20'
       ]

let formattedUserData = 

userData.forEach(user=>
  if(!formattedUserData[user.id]) formattedUserData[user.id]= 
    id: user.id,
    Time: [],
    Date: [],
  
  formattedUserData[user.id].Time.push(user.Time)
  formattedUserData[user.id].Date.push(user.Date)
)

const finalResponse = Object.entries(formattedUserData).map((e) => (  ...e[1]  ));
console.log("finalResponse",finalResponse)

【讨论】:

【参考方案2】:

编辑:修复通过使用 DateTime 字符串的 Set() 过滤重复的 DateTimes 以保持相应的顺序

注意:可选链接 ?. 需要 Chrome 80+ 和 Safari 13+。如果需要兼容性,请对未定义使用三元检查。

使用对象映射来跟踪重复的 id,如果找到,则连接到时间数组。

userData = [id:'101', Time:'3:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'6/25/20',
            id:'105', Time:'1:00pm', Date:'3/25/20',
            id:'105', Time:'5:00pm', Date:'5/25/20'
           ]
console.log(
Object.values(
userData.reduce((acc,Time, id, Date)=>
  // [id] exists and does not contain DateTime
  acc[id]?.TD?.has(`$Date_$Time`)!== true ? 
  Object.assign(acc, [id]:
      id, 
      TD: (acc[id]?.TD||new Set()).add(`$Date_$Time`),
      Time: (acc[id]?.Time||[]).concat(Time),
      Date: (acc[id]?.Date||[]).concat(Date)
   )
   : acc,)
)
// get rid of TD Set, used only to prevent dupes
.map((TD, ...o)=>o)
)

【讨论】:

预期结果需要对 TimeDate 数组进行重复数据删除,因此您的答案(尚未)100% 准确。【参考方案3】:

我做到了:

const userData = 
    [  id: '101', Time: '3:00pm', Date: '5/25/20' 
    ,  id: '101', Time: '5:00pm', Date: '5/25/20' 
    ,  id: '101', Time: '5:00pm', Date: '6/25/20' 
    ,  id: '105', Time: '1:00pm', Date: '3/25/20' 
    ,  id: '105', Time: '5:00pm', Date: '5/25/20' 
    ] 
      
const result = userData.reduce((a,id,Time,Date)=>
  let el = a.find(ud=>ud.id===id)
  if (!el)  el = id, Time:[], Date:[];  a.push(el) 
  if (!el.Time.includes(Time)) el.Time.push(Time)
  if (!el.Date.includes(Date)) el.Date.push(Date)
  return a
  , [])

console.log( JSON.stringify(result,0,2) )
.as-console-wrapper  max-height: 100% !important; 

【讨论】:

【参考方案4】:

根据MDN,Map 比使用Object 更合适。集合用于确保对所有值进行重复数据删除。

userData = [id:'101', Time:'3:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'5/25/20',
            id:'101', Time:'5:00pm', Date:'6/25/20',
            id:'105', Time:'1:00pm', Date:'3/25/20',
            id:'105', Time:'5:00pm', Date:'5/25/20',
           ];

const structure = new Map();

userData.forEach(el => 
  const t, d = structure.get(el.id) || t: new Set(), d: new Set();
  structure.set(el.id,  t: t.add(el.Time), d: d.add(el.Date) );
);

const restructured = 
  [...structure].map(el => ( id: el[0], Time: [...el[1].t], Date: [...el[1].d] ))

console.log(restructured)

【讨论】:

以上是关于重构 JSON 对象数组的主要内容,如果未能解决你的问题,请参考以下文章

重构表的对象数组

原生JavaScript对象数组去重,重构为对象{pro1:[hash], pro02: [hash]}

通过键在php中重构多维json

用 Javascript 中的键值对重构对象数组并输出或发出它以用 mongoose 和 MongoDB 保存它?

c# json对象中含有数组,数组中又含有数组!

json对象,如何表示数组