Redis值数据类型——list

Redis值数据类型——list

4.3 list

4.3.1 概述

  1. 存储内容

可存储有序的字符串列表;

  1. 常用操作

向列表两端添加元素、获取列表的某一个片段;

  1. 底层实现

基于双向链表(double linked list);

  1. 性能特性
  • 向列表两端添加元素的时间复杂度为 O (1);
  • 获取元素时,越接近列表两端的元素,访问速度越快;
  • 极端场景验证:即便列表包含几千万个元素,获取其头部或尾部的 10 条记录仍能达到极快的速度。

4.3.2 命令

  1. 向列表两端增加元素

执行 lpush/rpush 时,Redis 会自动创建这个列表,并将元素插入。如果列表存在就会在已有列表上进行操作。向列表(key)的左侧(头部) 增加一个 / 多个元素。多个值按传入顺序依次从左侧插入。

lpush key value [value ...]

向列表(key)的右侧(尾部) 增加一个 / 多个元素。

多个值按传入顺序依次从右侧插入。

rpush key value [value ...]

结果:3 → 2 → 1 → 4 → 5 → 6

  1. 从列表两端弹出元素
lpop key rpop key

lpop命令从列表左边弹出一个元素,会分两步完成。第一步是将列表左边的元素从列表中移除,第二步是返回被移除的元素值。rpop同理。

  1. 获取列表中元素个数
llen key

4.获取列表片段

lrange key start stop

lrange命令是列表类型最常用的命令之一,获取列表中的某一片段,将返回start、stop之间的所有元素(包含两端的元素),索引从0开始。索引可以是负数,如:“-1”代表最后边的一个元素。

  1. 删除列表中指定的值
lrem key count value

lrem命令会在列表里找值为value的元素,然后只删除其中的的前count个。根据count值的不同,该命令的执行方式会有所不同:

  • 当count>0时, LREM会从列表左边开始删除。
  • 当count<0时, LREM会从列表后边开始删除。
  • 当count=0时, LREM删除所有值为value的元素。
  1. 获取/设置指定索引的元素值
LINDEX key index LSET key index value
  1. 只保留列表指定片段

只保留列表指定片段,指定范围和LRANGE一致

LTRIM key start stop

8.向列表中插入元素

LINSERT key BEFORE|AFTER pivot value

该命令首先会在列表中从左到右查找值为pivot的元素,然后根据第二个参数是BEFORE还是AFTER来决定将value插入到该元素的前面还是后面。

  1. 将元素从一个列表转移到另一个列表中

先从 source 列表的右侧(尾部) 弹出一个元素。再把这个元素插入到 destination 列表的左侧(头部)。返回被移动的元素。

RPOPLPUSH source destination

4.3.3 方法

  1. List 类型核心操作
功能
StringRedisTemplate 方法
对应 Redis 命令
代码中的作用
右侧(尾部)添加元素
opsForList().rightPush(key, value)
rpush
向列表尾部追加单个元素
左侧(头部)添加元素
opsForList().leftPush(key, value)
lpush
向列表头部插入单个元素(最新元素在头部,适合评论 / 消息场景)
获取指定范围元素
opsForList().range(key, start, end)
lrange
获取列表中
start
end
下标元素(
0,-1
表示所有元素,
0,3
表示前 4 个)
获取列表长度
opsForList().size(key)
llen
返回列表的元素总个数
修改指定下标值
opsForList().set(key, index, value)
lset
更新列表中指定下标位置的元素值
获取指定下标值
opsForList().index(key, index)
lindex
查询列表中指定下标位置的元素值
删除指定数量的目标值
opsForList().remove(key, count, value)
lrem
按方向删除
count
个值为
value
的元素(
count>0
从左删,
count=0
删所有)
截取列表保留指定区间
opsForList().trim(key, start, end)
ltrim
仅保留列表中
start
end
下标元素,删除区间外所有元素
左侧(头部)出栈
opsForList().leftPop(key)
lpop
从列表头部弹出元素(元素从列表中移除,返回弹出值)
  1. List 关联的通用操作
功能
StringRedisTemplate 方法
对应 Redis 命令
代码中的作用
删除整个列表
delete(key)
del
直接删除列表键,清空列表所有元素
清空当前数据库
getConnectionFactory().getConnection().flushDb()
flushdb
清空当前 Redis 库的所有键(含 List、Hash、String 等所有类型)
  1. 结论
  • List 类型操作的核心套路:stringRedisTemplate.opsForList().xxx();
  • 方向相关:rightPush/leftPush 对应 “尾加 / 头加”,leftPop 对应 “头出”,符合 Redis List 双向链表特性;
  • 范围操作:range/trim 的下标规则和 Redis 一致(从 0 开始,-1 表示最后一个元素);
  • 删除逻辑:remove 仅删除 “值匹配” 的元素,count 控制删除数量和方向,而非删除列表下标元素。
  1. 代码
package com.qcby.springbootredis; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.List; @SpringBootTest public class ListTest { // 注入 SpringBoot 自带的 StringRedisTemplate(替代 Jedis,自动管理连接池) @Autowired private StringRedisTemplate stringRedisTemplate; /** * List 类型核心操作(对应原 Jedis 的 testList 方法) */ @Test public void testList() { System.out.println("==List=="); try { // ========== 1. 移除指定 list 的所有内容========== stringRedisTemplate.delete("messages"); // ========== 2. 向 list 右侧(尾部)添加元素 ========== stringRedisTemplate.opsForList().rightPush("messages", "Hello how are you?"); stringRedisTemplate.opsForList().rightPush("messages", "Fine thanks. I'm having fun with redis."); stringRedisTemplate.opsForList().rightPush("messages", "I should look into this NOSQL thing ASAP"); // ========== 3. 获取 list 所有元素 ========== // 0 = 起始下标,-1 = 结束下标(表示所有元素) List<String> values = stringRedisTemplate.opsForList().range("messages", 0, -1); System.out.println("messages 所有元素:" + values); // ========== 4. 清空当前数据库 ========== stringRedisTemplate.getConnectionFactory().getConnection().flushDb(); System.out.println("清空当前数据库成功"); // ========== 5. 向 list 左侧(头部)添加元素 ========== stringRedisTemplate.opsForList().leftPush("lists", "vector"); stringRedisTemplate.opsForList().leftPush("lists", "ArrayList"); stringRedisTemplate.opsForList().leftPush("lists", "LinkedList"); // ========== 6. 获取 list 长度 ========== Long listSize = stringRedisTemplate.opsForList().size("lists"); System.out.println("lists 长度:" + listSize); // ========== 7. 获取 list 指定范围元素 ========== List<String> rangeValues = stringRedisTemplate.opsForList().range("lists", 0, 2); System.out.println("lists 0-2 范围元素:" + rangeValues); // ========== 8. 修改 list 指定下标的值 ========== stringRedisTemplate.opsForList().set("lists", 0, "hello list!"); System.out.println("修改 lists 下标 0 的值为 hello list! 成功"); // ========== 9. 获取 list 指定下标的值(对应 jedis.lindex("lists", 1)) ========== String indexValue = stringRedisTemplate.opsForList().index("lists", 1); System.out.println("lists 下标 1 的值:" + indexValue); // ========== 10. 删除 list 中指定数量的目标值 ========== // 参数:key、删除数量(count)、目标值(value)→ 从左删 1 个 "vector" Long removeCount = stringRedisTemplate.opsForList().remove("lists", 1, "vector"); System.out.println("删除 lists 中 vector 的数量:" + removeCount); // ========== 11. 截取 list 保留指定区间,删除区间以外的数据 ========== stringRedisTemplate.opsForList().trim("lists", 0, 1); System.out.println("截取 lists 0-1 区间,删除其他元素成功"); // ========== 12. list 左侧(头部)出栈 ========== String leftPopValue = stringRedisTemplate.opsForList().leftPop("lists"); System.out.println("lists 左侧出栈元素:" + leftPopValue); // ========== 13. 再次获取 list 所有元素,查看最终结果 ========== List<String> finalValues = stringRedisTemplate.opsForList().range("lists", 0, -1); System.out.println("lists 最终剩余元素:" + finalValues); } catch (Exception e) { e.printStackTrace(); } } /** * 商品评论列表业务场景实现 */ @Test public void testGoodsCommentList() { // 1. 定义商品评论列表 key(商品 1001 的评论) String goodsCommentKey = "items:comment:1001"; // 2. 模拟用户发布商品评论(将评论转为 JSON 字符串,左侧插入List → 最新评论在头部) String comment1 = "{\"id\":1,\"name\":\"商品不错,很好!!\",\"date\":1430295077289}"; String comment2 = "{\"id\":2,\"name\":\"质量很好,性价比高\",\"date\":1430295177289}"; stringRedisTemplate.opsForList().leftPush(goodsCommentKey, comment1); stringRedisTemplate.opsForList().leftPush(goodsCommentKey, comment2); // 3. 模拟页面查询评论列表(从 Redis 中取出所有评论 JSON 数据) List<String> goodsComments = stringRedisTemplate.opsForList().range(goodsCommentKey, 0, -1); // 4. 打印展示评论列表(实际开发中可反序列化为对象,返回给前端页面) System.out.println("商品 1001 评论列表:"); for (String comment : goodsComments) { System.out.println(comment); } } }

Read more

优雅反转链表:LeetCode 206题深度解析与艺术实现

优雅反转链表:LeetCode 206题深度解析与艺术实现

🌟 优雅反转链表:LeetCode 206题深度解析与艺术实现 🌟 * 视频地址 * 🎨 链表反转的艺术 * 🧠 算法思路图解 * 🔍 核心思想三指针法 * 💻 代码实现详解 * 📝 代码关键点解析 * 🏆 性能分析 * 🌈 变式与扩展 * 💡 总结与思考 视频地址 因为想更好的为大佬服务,制作了同步视频,这是Bilibili的视频地址 链表操作是算法学习中的基础必修课,而反转链表更是其中最经典的练习题之一。今天,我们将以LeetCode 206题为例,深入探讨如何优雅地实现单链表的反转操作,并分析其中的精妙之处。 🎨 链表反转的艺术 链表反转,看似简单,实则蕴含着指针操作的精髓。就像一位舞者优雅地转身,链表中的节点也需要流畅地改变它们的指向关系。让我们先来欣赏一下这个"舞蹈"的基本步骤。 🧠 算法思路图解 原始链表 1 --> 2 --> 3 --> 4 --> 5 --&

By Ne0inhk
【数据结构入坑指南(四.2)】--《从单链到双链的进阶,读懂“双向奔赴”的算法之美与效率权衡》

【数据结构入坑指南(四.2)】--《从单链到双链的进阶,读懂“双向奔赴”的算法之美与效率权衡》

🔥@晨非辰Tong:个人主页  👀专栏:《C语言》、《数据结构与算法》、《数据结构与算法刷题集》 💪学习阶段:C语言、数据结构与算法初学者 ⏳“人理解迭代,神理解递归。” 引言:征服了单链表,却总感束缚?无法回溯的遍历、繁琐的节点删除...是时候解锁双向链表,体验指针自由穿梭的真正力量。 目录 一、链表的分类、说明 1.1  带头、不带头 1.2  单向、双向 1.3  循环、不循环 二、双向链表 2.1  基本信息介绍 2.1  定义、结构 2.2  “哨兵位”的初始化(准备工作) 2.2

By Ne0inhk