完善排行榜的排序规则


在之前的一篇博客中,讨论了如何合并两个排行榜。

但代码上有一些瑕疵,就是排序的规则写得异常的简陋:

std::sort(tmp_list.begin(), tmp_list.end(), [](const auto &lhs, const auto &rhs) { return lhs.capability > rhs.capability; });

假如遇到相同战力的,那么又该如何排序呢?通常在业务上,会有一个规则:谁先上榜,谁排前面。也就是记录一个上榜时间,谁的时间小,谁的优先级高。

那么代码可能是这样的:

struct CapabilityRankItem
{
	int uid = 0;
	long long capability = 0;
	std::string name;
	unsigned int refresh_timestamp = 0;
};

bool operator<(const CapabilityRankItem &lhs, const CapabilityRankItem& rhs)
{
	// 如何定义 lhs的优先级高于rhs
	if (lhs.capability != rhs.capability)
	{
		return lhs.capability > rhs.capability;
	}
	else
	{
		if (lhs.refresh_timestamp != rhs.refresh_timestamp)
		{
			return lhs.refresh_timestamp < rhs.refresh_timestamp;
		}
		else
		{
			return lhs.uid > rhs.uid;
		}
	}
}

注意,上述代码存在着一个不太容易发掘的问题。即判断 refresh_timestamp 时未判断与0值的判断,即0值是一个无效值,应表示未刷新过。但它又是最小,因此表示优先级高。但业务上,显然是优先级低的。

比如:

std::vector rank_list =
{
	{ 2, 99, "张飞" },
	{ 3, 96, "赵云" },
	{ 5, 93, "黄忠" },
	{ 4, 94, "马超" },
	{ 10, 100, "关羽" },
	{ 8, 100, "吕布", 10000 },
};

关羽和吕布对比,由于吕布刷新时间是10000,关羽是0,应当吕布排前。但实际上确是关羽排前。

解决这个问题的方法就是判断一下0:

bool operator<(const CapabilityRankItem &lhs, const CapabilityRankItem& rhs)
{
	// 如何定义 lhs的优先级高于rhs
	if (lhs.capability != rhs.capability)
	{
		return lhs.capability > rhs.capability;
	}
	else
	{
		if (lhs.refresh_timestamp != rhs.refresh_timestamp && lhs.refresh_timestamp != 0 && rhs.refresh_timestamp != 0)
		{
			return lhs.refresh_timestamp < rhs.refresh_timestamp;
		}
		else
		{
			return lhs.uid < rhs.uid;
		}
	}
}

这样就正确了。完整测试代码如下:


#include 
#include 
#include 
#include 

struct CapabilityRankItem
{
	int uid = 0;
	long long capability = 0;
	std::string name;
	unsigned int refresh_timestamp = 0;
};

bool operator<(const CapabilityRankItem &lhs, const CapabilityRankItem& rhs)
{
	// 如何定义 lhs的优先级高于rhs
	if (lhs.capability != rhs.capability)
	{
		return lhs.capability > rhs.capability;
	}
	else
	{
		if (lhs.refresh_timestamp != rhs.refresh_timestamp && lhs.refresh_timestamp != 0 && rhs.refresh_timestamp != 0)
		{
			return lhs.refresh_timestamp < rhs.refresh_timestamp;
		}
		else
		{
			return lhs.uid < rhs.uid;
		}
	}
}

std::vector rank_list =
{
	{ 2, 99, "张飞" },
	{ 3, 96, "赵云" },
	{ 5, 93, "黄忠" },
	{ 4, 94, "马超" },
	{ 10, 100, "关羽" },
	{ 8, 100, "吕布", 10000 },
};

int main()
{
	std::sort(rank_list.begin(), rank_list.end());

	for (const auto& item : rank_list)
	{
		std::cout << item.name << " " << item.capability << std::endl;
	}

	std::cin.get();
}