【Android】【算法】实现在一堆房间名称数据获取房间名称数目排名前十的一个列表数据,且第一个item必须是名称最新且数目最多的

背景

客户有一个这样的需求:
在一个房间列表中有一堆不同名字的房间名,但是总会有名字相同的几个房间名。那么就在一个Adapter中显示当前房间列表中前十位名称一致的数据。

那么就意味着需要构建一个长度为10的数据结构,该结构中至少包含该房间名称和 相同房间名称的数目。
那么就得遍历整个的原始房间名称数据。简化来说:就是一个列表,列表包括各种各样的名字。

客户想要的就是这里面名字出现次数排在前十的房间名称。

思路

算法实现:

  • 需要建立一个kv对即散列表,存储当前的名称和其对应的数目;

这个实现就比较简单,就是遍历整个的房间名,如果有增加,就put进去;反之就忽略。

  // 遍历获取数据
        for (RoomInfo roomInfo : roomList) {
            String roomName = roomInfo.getSubject();
            // 添加 前缀展示
            String roomNameWithPremix = RoomNameListAdapter.ROOM_PREMIX + roomName;
            if (roomNameCountMap.containsKey(roomNameWithPremix)) {
                int count = roomNameCountMap.get(roomNameWithPremix);
                count++;
                roomNameCountMap.put(roomNameWithPremix, count);
            } else {
                roomNameCountMap.put(roomNameWithPremix, 1);
            }
        }

这也是我第一次使用这个对象,还有很多的不懂。
详细可以查阅官方文档在这里插入图片描述

重点是 比较器的类型:
在这里插入图片描述

PriorityQueue<RoomNameCountPair> queue = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            queue = new PriorityQueue<>(Comparator.comparingInt(RoomNameCountPair::getCount));
        }

其中::的使用可以参考在这里插入图片描述

  • 最终代码

    HashMap<String, Integer> roomNameCountMap = new HashMap<>();

    List<String> subjectWithTopTen = new ArrayList<>();

    private List<String> getTopRoomNameList(List<RoomInfo> roomList, int limit) {
        // 重新刷
        roomNameCountMap.clear();
        subjectWithTopTen.clear();
        if (roomList.isEmpty()) {
            return subjectWithTopTen;
        }
        // 遍历获取数据
        for (RoomInfo roomInfo : roomList) {
            String roomName = roomInfo.getSubject();
            // 添加 前缀展示
            String roomNameWithPremix = RoomNameListAdapter.ROOM_PREMIX + roomName;
            if (roomNameCountMap.containsKey(roomNameWithPremix)) {
                int count = roomNameCountMap.get(roomNameWithPremix);
                count++;
                roomNameCountMap.put(roomNameWithPremix, count);
            } else {
                roomNameCountMap.put(roomNameWithPremix, 1);
            }
        }

        // 优先队列 queue 来对房间名称出现次数进行排序
        PriorityQueue<RoomNameCountPair> queue = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            queue = new PriorityQueue<>(Comparator.comparingInt(RoomNameCountPair::getCount));
        }

        for (Map.Entry<String, Integer> entry : roomNameCountMap.entrySet()) {
            queue.offer(new RoomNameCountPair(entry.getKey(), entry.getValue()));
            // 是否大于限制的10个,如果是就弹出最高优先级的
            if (queue.size() > limit) {
                queue.poll();
            }
        }

        while (!queue.isEmpty()) {
            subjectWithTopTen.add(0, queue.poll().getRoomName());
        }

        return subjectWithTopTen;
    }

如何理解PriorityQueue

假设有以下的 mock 数据:

roomNameCountMap = {
  "room1": 5,
  "room2": 3,
  "room3": 2,
  "room4": 7,
  "room5": 1,
  ...
  // 共有20个键值对
}

在代码执行过程中,queue 内的实际数据的内容会如下变化:

  1. 初始状态:queue 为空。
  2. 创建 PriorityQueue 对象时,指定了一个比较器 Comparator.comparingInt(RoomNameCountPair::getCount),它会根据 RoomNameCountPair 对象的 count 属性进行排序。
  3. 第一次循环迭代:
    • 将 “room1” 和对应的计数值 5 封装为 RoomNameCountPair 对象,加入 queue
    • queue 中的内容为 [(room1, 5)]
  4. 第二次循环迭代:
    • 将 “room2” 和对应的计数值 3 封装为 RoomNameCountPair 对象,加入 queue
    • queue 中的内容为 [(room2, 3), (room1, 5)]
  5. 第三次循环迭代:
    • 将 “room3” 和对应的计数值 2 封装为 RoomNameCountPair 对象,加入 queue
    • queue 中的内容为 [(room3, 2), (room1, 5), (room2, 3)]
  6. 第四次循环迭代:
    • 将 “room4” 和对应的计数值 7 封装为 RoomNameCountPair 对象,加入 queue
    • queue 中的内容为 [(room3, 2), (room2, 3), (room1, 5), (room4, 7)]
  7. 第五次循环迭代:
    • 将 “room5” 和对应的计数值 1 封装为 RoomNameCountPair 对象,加入 queue
    • queue 中的内容为 [(room5, 1), (room3, 2), (room2, 3), (room1, 5), (room4, 7)]
  8. 接下来的循环迭代会继续按照计数值的大小插入元素,并在 queue 的大小超过限制时,弹出计数值最小的元素。最终,queue 中会保留计数值最大的前 limit 个元素。

由于我们在创建 PriorityQueue 对象时指定了比较器,因此 queue 中的元素会根据计数值从小到大进行排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值