diff --git a/lib/competition_ranking_leaderboard.rb b/lib/competition_ranking_leaderboard.rb index 4e10905..95f7a96 100644 --- a/lib/competition_ranking_leaderboard.rb +++ b/lib/competition_ranking_leaderboard.rb @@ -67,29 +67,36 @@ def ranked_in_list_in(leaderboard_name, members, options = {}) end end unless leaderboard_options[:members_only] + included_members = [] + scores = [] + members.each_with_index do |member, index| data = {} data[@member_key] = member unless leaderboard_options[:members_only] data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1] + if data[@score_key] == nil next unless leaderboard_options[:include_missing] end - - if @reverse - data[@rank_key] = @redis_connection.zcount(leaderboard_name, '-inf', "(#{data[@score_key]}") + 1 rescue nil - else - data[@rank_key] = @redis_connection.zcount(leaderboard_name, "(#{data[@score_key]}", '+inf') + 1 rescue nil - end end - if leaderboard_options[:with_member_data] - data[@member_data_key] = member_data_for_in(leaderboard_name, member) - end + included_members << member + scores << data[@score_key] ranks_for_members << data end + if leaderboard_options[:with_member_data] + members_data_for_in(leaderboard_name, included_members).each_with_index do |member_data, index| + ranks_for_members[index][@member_data_key] = member_data + end + end + + rankings_for_members_having_scores_in(leaderboard_name, included_members, scores).each_with_index do |rank, index| + ranks_for_members[index][@rank_key] = rank + end + case leaderboard_options[:sort_by] when :rank ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] } @@ -99,4 +106,26 @@ def ranked_in_list_in(leaderboard_name, members, options = {}) ranks_for_members end -end \ No newline at end of file + + protected + + # Retrieve a list of the rankings of leaders given their member names and scores + # + # @param leaderboard_name [String] Name of the leaderboard. + # @param members [Array] Member names. + # @param scores [Array] a list of scores for the members, aligned with the member names + # + # @return a list of the rankings for the passed in members and scores + def rankings_for_members_having_scores_in(leaderboard_name, members, scores) + @redis_connection.multi do |transaction| + members.each_with_index do |member, index| + if @reverse + transaction.zcount(leaderboard_name, '-inf', "(#{scores[index]}") + else + transaction.zcount(leaderboard_name, "(#{scores[index]}", '+inf') + end + end + end.map{|rank| rank ? rank + 1 : rank} + end + +end diff --git a/lib/leaderboard.rb b/lib/leaderboard.rb index 66efd81..a5f2ed7 100644 --- a/lib/leaderboard.rb +++ b/lib/leaderboard.rb @@ -219,6 +219,25 @@ def member_data_for_in(leaderboard_name, member) @redis_connection.hget(member_data_key(leaderboard_name), member) end + # Retrieve the optional member data for a given member in the named leaderboard. + # + # @param leaderboard_name [String] Name of the leaderboard. + # @param members [Array] Member names. + # + # @return array of strings of optional member data. + def members_data_for_in(leaderboard_name, members) + @redis_connection.hmget(member_data_key(leaderboard_name), *members) + end + + # Retrieve the optional member data for the given members in the leaderboard. + # + # @param members [Array] Member names. + # + # @return array of strings of optional member data. + def members_data_for(members) + members_data_for_in(@leaderboard_name, members) + end + # Update the optional member data for a given member in the leaderboard. # # @param member [String] Member name. @@ -964,13 +983,15 @@ def ranked_in_list_in(leaderboard_name, members, options = {}) data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1] end - if leaderboard_options[:with_member_data] - data[@member_data_key] = member_data_for_in(leaderboard_name, member) - end - ranks_for_members << data end + if leaderboard_options[:with_member_data] + members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index| + ranks_for_members[index][@member_data_key] = member_data + end + end + case leaderboard_options[:sort_by] when :rank ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] } diff --git a/lib/tie_ranking_leaderboard.rb b/lib/tie_ranking_leaderboard.rb index 336ef3f..aa7b037 100644 --- a/lib/tie_ranking_leaderboard.rb +++ b/lib/tie_ranking_leaderboard.rb @@ -249,13 +249,15 @@ def ranked_in_list_in(leaderboard_name, members, options = {}) end end - if leaderboard_options[:with_member_data] - data[@member_data_key] = member_data_for_in(leaderboard_name, member) - end - ranks_for_members << data end + if leaderboard_options[:with_member_data] + members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index| + ranks_for_members[index][@member_data_key] = member_data + end + end + case leaderboard_options[:sort_by] when :rank ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }