C#如何统计多个List<int>中频次最高的连续3元素集合
C# 实现最多客户连续阅读3本图书的统计方案
核心实现逻辑
我们采用固定长度滑动窗口+频次去重统计的思路实现,要注意统计规则:同一客户的阅读记录中,按阅读顺序相邻的3本图书才算有效连续序列,同一客户重复出现相同序列只计数1次,最终取覆盖客户数最多的序列即可。
具体执行步骤
- 初始化统计容器:使用值类型元组
(int, int, int)作为连续3本图书的序列键,用HashSet<string>存储对应客户ID,自动完成同客户的去重,避免重复计数。 - 遍历全量客户阅读记录:
- 若当前客户的已读书籍列表长度小于3,直接跳过,无法凑出有效3本序列
- 以3为固定窗口大小,从书籍列表头部开始逐位滑动,每次取出窗口内的3个书籍ID组成序列键
- 将当前客户ID加入该序列键对应的客户集合中,若序列不存在则先初始化集合
- 排序取Top1:遍历完成后,按每个序列对应的客户集合大小降序排序,排在第一位的就是覆盖客户最多的连续3本图书序列。
可运行代码示例
using System; using System.Collections.Generic; using System.Linq; class BookSequenceCalculator { static void Main() { // 示例输入数据:Key为客户ID,Value为按阅读顺序排列的已读书籍ID列表 var customerReadMap = new Dictionary<string, List<int>> { ["c1"] = new List<int> {1, 2, 3, 6}, ["c2"] = new List<int> {3, 5}, ["c3"] = new List<int> {1, 2, 3, 4} }; // 序列统计字典 var sequenceStat = new Dictionary<(int first, int second, int third), HashSet<string>>(); foreach (var (customerId, bookIds) in customerReadMap) { // 书籍数量不足3本直接跳过 if (bookIds.Count < 3) continue; // 滑动窗口生成所有连续3本的序列 for (int i = 0; i <= bookIds.Count - 3; i++) { var currentTriplet = (bookIds[i], bookIds[i+1], bookIds[i+2]); if (!sequenceStat.ContainsKey(currentTriplet)) { sequenceStat[currentTriplet] = new HashSet<string>(); } sequenceStat[currentTriplet].Add(customerId); } } // 取客户数最高的序列 var topResult = sequenceStat.OrderByDescending(kv => kv.Value.Count).First(); // 输出结果:1,2,3,覆盖客户数2,和预期一致 Console.WriteLine($"覆盖客户最多的连续3本图书序列为:{topResult.Key.first},{topResult.Key.second},{topResult.Key.third}"); Console.WriteLine($"覆盖客户数:{topResult.Value.Count}"); } }
边界说明
- 如果存在多个序列覆盖客户数相同的情况,可以追加二级排序规则,比如按书籍ID升序排列取第一个,避免结果随机。
- 如果业务上不需要考虑阅读顺序,只统计3本图书的组合,只需要在生成序列键前先对窗口内的3个ID做升序排序,再生成元组作为key即可。
内容的提问来源于stack exchange,提问作者Lavanya Balasubramanian
相关产品推荐
相关产品推荐

