繁体   English   中英

JavaScript键上的对象排序数组

[英]Javascript sort array of objects on key

我有一个对象数组(来自ajax / PDO调用),如下所示:

signincounts: [{ status: 1
   count:  3
   teamid: 4
 },{
   status: 0
   count:  1
   teamid: 2
 },{
   status: 0
   count:  2
   teamid: 4
}]

这些对象代表登录特定事件的用户数:

  • 状态= 1(已登录,将参加)
  • 状态= 0(退出,将不参加)
  • count = x登录/注销的人数
  • teamid = y他们所属的团队

另外,我还有以下信息:

teamcount : {
    2: 5
    4: 6
}
  • teamid:玩家总数

我现在想在Javascript中对它进行排序,以显示登录状态,如下所示:

小组2:登录/退出/尚未决定

小组4:已登录/已退出/尚未决定

在这种情况下,将是:

小组2:0/1/4

小组4:3/2/1

难点:

  • teamid是唯一的,但不一定是顺序的
  • 如果状态的计数为零,则不属于返回的JSON的一部分
  • 对象不一定是有序的
  • 可以有两个到几十个团队
  • 字符串输出应按teamid排序,查看者的团队在顶部(还有一个附加变量playerteamid,可用于简单地进行检查)

我当时想我需要对它进行排序,但是由于未定义的零计数和不连续的团队标识,因此不确定如何进行处理。 我最初的计划是使用两个空数组(signin_count,signout_count),然后遍历ajax JSON并将计数推入其中(如果是玩家团队,则不移位)。 但是,如何在其中保留teamid参考和未定义的值(因此索引保持“平行”)? 而且我假设无论如何(在对象数组级别本身)有一种更干净,更好的方法,这将允许我将其直接排序到结果字符串中。

也尝试过搜索,但没有找到有关考虑特定键/值对的双重排序问题。

对于某些指示会很高兴。

好吧! 让我们分两个阶段进行操作:

过滤阶段

首先,我们必须消除不应打印的条目。 您提到的计数等于0

data = data.filter(function(entry) { entry.count > 0 })

分选阶段

现在,将打印data中所有剩余的条目,我们可以将它们按所需顺序排序。 您提到了两个约束:

  • 较低的团队ID应该首先显示
  • 特定的团队ID应始终显示在顶部

使用具有以下签名的比较函数来调用Javascript Array对象的.sort()方法:

function compare(a, b) returns Number

返回的Number解释如下:

  • 如果compare返回< 0 ,则ab之前
  • 如果compare返回> 0 ,则ba之前
  • 如果compare返回0 ,则没关系(通常遵循先前的顺序)

因此,让我们编写一个可以对数据进行排序的compare函数:

function compare(a, b) {
  // The special USER_TEAM_ID goes before any other element:
  if (a.teamId === USER_TEAM_ID) return -1

  // For any other case:
  return a.teamId - b.teamId // invert these to reverse the sort
}

现在您可以致电:

data.sort(compare)

两步:

  • 首先,迭代teamcount并创建一个对象teamid => [0, 0, count] 换句话说,假设所有团队成员都不确定

  • 然后,迭代signincounts并执行两件事:将c.count添加到result[teamid]的相应插槽中,并从result[teamid][undecided]减去c.count result[teamid][undecided]

这为您提供了所需的统计信息,最终的排序和输出留给读者。

码:

 data = { signincounts: [{ status: 1, count: 3, teamid: 4 }, { status: 0, count: 1, teamid: 2 }, { status: 0, count: 2, teamid: 4 }] , teamcount: { 2: 5, 4: 6 } }; res = {} Object.keys(data.teamcount).forEach(teamid => res[teamid] = [0, 0, data.teamcount[teamid]]); data.signincounts.forEach(c => { res[c.teamid][c.status] = c.count; res[c.teamid][2] -= c.count; }); console.log(res) 

我认为lodash在这里会为您服务。

 var signincounts = [{ status: 1, count: 3, teamid: 4 },{ status: 0, count: 1, teamid: 2 },{ status: 0, count: 2, teamid: 4 }], teamcount = { 2: 5, 4: 6 }; var result = _.chain(signincounts) .groupBy('teamid') .mapValues(mapTeams).value(); console.log(result); // helper function for mapping from grouped data function mapTeams(teamData, teamid) { var team = {}; team.undecided = teamcount[teamid]; var signed_in = _.find(teamData, {status: 1}), // gets the object that tells us how many are signed in signed_out = _.find(teamData, {status: 0}); // gets the object that tells us how many are signed out team.signed_in = (signed_in && signed_in.count) ? signed_in.count : 0; // guard against undefined team.signed_out = (signed_out && signed_out.count) ? signed_out.count : 0; // guard against undefined team.undecided -= (team.signed_in + team.signed_out); return team; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.min.js"></script> 

所以这就是正在发生的事情。 首先我们调用_.chain(signincounts) 这意味着我们将采用登录计数,并将其通过一系列函数进行传递,每个函数都会修改前一个函数的结果。 因此,在发出我们要链接的信号后,我们按其teamid将数组中的所有对象teamid 我们得到以下对象:

{ '2': [ { status: 0, count: 1, teamid: 2 } ],
  '4':
   [ { status: 1, count: 3, teamid: 4 },
     { status: 0, count: 2, teamid: 4 } ] }

因为我们正在链接,所以这就是传递给mapValues mapValues根据传入的回调函数创建一个具有与传入的对象相同的键,但具有不同值的新对象。因此,我们的结果将是一个以小队号作为键的对象,这就是我所希望的。 helper函数定义将映射到每个teamid的内容。 对于每个键值对执行此辅助函数。

在helper函数内部,我们创建一个对象,该对象将成为新的teamid映射。 因此,对于每个teamid,我们将返回一个看起来像{ signed_in: <Number>, signed_out: <Number>, undecided: <Number> } 我们未定为团队总数。 然后,我们从先前的结果中找到数组中的对象,该结果告诉我们该团队有多少人参加,然后我们找出有多少人没有参加。 我们相应地分配了signed_insigned_out字段。 然后,我们从总数中减去signed_in和signed_out的数目,以获得未定的计数。

暂无
暂无

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

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