在前几篇我们介绍了Redis类型中的字符串类型和哈希类型,今天我们了解一下Redis中的列表类型。在Redis中列表类型,可以简单的理解为存储多个有序字符串的一种新类型,这种类型除了字符串类型中已有的功能外,还提供了其它的功能。如可以对列表的两端插入和弹出元素(在列表中的字符串都可以称之为元素),除此之外还可以获取指定的元素列表,并且还可以通过索引下标获取指定元素等等。下面我们通过下图来看一下Redis中列表类型的插入和弹出操作:
下面我们看一下Redis中列表类型的获取与删除操作:
下面我们看一下Redis列表类型的特点:
- 列表中所有的元素都是有序的。所以在Redis中列表类型是可以通过索引获取的,也就是上图中的
lindex命令
并且在Redis中列表类型的索引是从0开始的。
- 列表中的元素是可以重复的。也就是说在Redis列表类型中,是可以保存重复的元素,也就是如下图所示:
下面我们还是和学习其它数据类型一样,我们还是先学习一下Redis列表类型的命令。
命令
一、添加操作
1.从右边插入元素
rpush key value [value ...]
我们看rpush命令在插入时,是有返回值的,返回值的数量就是当前列表中所有元素的个数。
我们也可以用下面的命令从左到右获取当前列表中的所有的元素,也就是如上图所示中那样。
lrange 0 -1
2.从左边插入元素
lpush key value [value ...]
lpush命令的返回值及用法和rpush命令一样,这里就不在介绍了,但通过上面的事例证明了我们前面说的,因为当前key中已经有了3个元素了,所以我们在执行插入命令时,返回的就是6而不是3,因为rpush命令和lpush命令的返回值并不是当前插入元素的个数,而返回的是当前key中全部元素的个数。
3.向某个元素前或者后插入元素
linsert key BEFORE|AFTER pivot value
linsert命令在执行的时候首先会从当前列表中查找到pivot元素,其次在将这个新元素插入到pivot元素的前面或者后面。并且我们通过上图所示知道linsert命令在执行成功后也是会有返回值的,返回的结果就是当前列表中元素的个数。
二、查找
1.获取指定范围内的元素列表
lrange key start stop
lrange命令会获取列表中指定索引范围的所有元素。通过索引获取列表主要有两个特点:
- 索引下标从左到右分别是0到N-1,从右到左是-1到-N。
- lrange命令中的end参数在执行时会包括当前元素的。并不是所有的语言都是这样的。如我们要获取列表中前两个元素则可以如下图所示:
2.获取列表中指定索引下标的元素
lindex key index
3.获取列表长度
llen key
三、删除
1.从列表左侧弹出元素
lpop key
lpop命令执行成功后会返回当前被删除的元素名称。
2.从列表右侧弹出元素
rpop key
rpop命令和lpop命令的使用方式一样,这里不在做过多介绍了。
3.删除指定元素
lrem key count value
lrem命令会将列表中等于value的元素删除掉,并且会根据count参数,来决定删除value的元素个数。下面我们看一下count参数的使用说明:
- count > 0:表示从左到右,最多删除count个元素。也就是如下图所示:
我们看上图中的命令中,虽然我们将count参数指定的是5,将value参数指定的是2,但由于当前列表中只有一个2,所以,当前lrem命令最多只能删除1个元素,并且lrem命令也是有返回值的,也就是当前成功删除元素的个数。
- count < 0:从右到左,最多删除count个元素。
- count = 0:删除所有元素。
4.按照索引范围修剪列表
ltrim key start stop
ltrim命令会直接保留start索引到stop索引的之间的元素,并包括当前元素,而之外的元素则都会删除掉,所以该命令也叫修剪列表。
并且有一点要注意ltrim命令不会返回当前的列表中元素的个数,而是返回改命令是否成功的状态。
四、修改
1.修改指定索引下标的元素
lset key index value
五、阻塞操作
blpop key [key ...] timeout
brpop key [key ...] timeout
blpop和brpop命令是lpop和rpop命令的阻塞版本,它们除了弹出方向不同以外,使用方法基本相同。
- key [key ...]:可以指定多个列表的键。
- timeout:阻塞时间(单位:秒)
下面我们看一下该命令的详细使用。
- 列表为空:如果timeout=3,则表示客户端等待3秒后才能返回结果,如果timeout=0,则表示客户端会一直等待,也就是会阻塞。
由于我期间向列表中插入了元素,否则上述命令将一直阻塞下去。
2.列表不为空:如果timeout=0,并且列表不为空时,则blpop和brpop命令会立即返回结果,不会阻塞。
下面我们看一下blpop和brpop命令的注意事项。
- 如果使用blpop和brpop命令指定多个键时,blpop和brpop命令会从左到右遍历键,并且一旦有一个键能返回元素,则客户端会立即返回。
当列表为空时,上述命令会阻塞,如果向上述中的任何一个键中插入元素,则上述命令会直接返回该键的元素。
- 如果多个客户端都对同一个键执行blpop或者brpop命令,则最先执行该命令的客户端会获取到该键的元素。
我同时启动了3个客户端,因为当前列表为空,所以上述命令执行后会阻塞。如果此时我向该列表中插入元素,则只有第一个客户端会有返回结果,因为第一个客户端是第一个执行上述命令的。
下面我们看一下列表中命令的相关时间复杂度。
操作类型 | 命令 | 时间复杂度 |
---|---|---|
添加 | rpush key value [value ...] | O(k),k是元素的个数 |
添加 | lpush key value [value ...] | O(k),k是元素的个数 |
添加 | linsert key BEFORE/AFTER pivot value | O(n),n是pivot距离列表头或者尾的距离 |
添加 | lrange key start stop | O(s + n),s是start偏移量,n是start到stop的范围 |
添加 | lindex key index | O(n),n是索引的偏移量 |
添加 | llen key | O(1) |
添加 | lpop key | O(1) |
添加 | rpop key | O(1) |
添加 | lrem key count value | O(n),n是列表长度 |
添加 | ltrim key start stop | O(n),n是要裁剪的元素个数 |
添加 | lset key index value | O(n),n是索引的偏移量 |
添加 | blpop/brpop key [key ...] timeout | O(1) |
内部编码
列表中的内部编码有两种,它们分别是:
- ziplist(压缩列表):当列表中元素个数小于512(默认)个,并且列表中每个元素的值都小于64(默认)个字节。Redis会选择用ziplist来作为列表的内部实现来减少内存的使用。当然上述默认值也可以通过相关参数修改:list-max-ziplist-entried(元素个数)、list-max-ziplist-value(元素值)。
- linkedlist(链表):当列表类型无法满足ziplist条件时,Redis会选择用linkedlist作为列表的内部实现。
下面我们通过相关命令来验证上述所说。
1.当元素个数较少并且没有大元素时,内部编码为ziplist。
我们看当我们在列表中插入少量元素,并且没有大元素时,返回的内部编码并不是ziplist而是quicklist。这又是什么编码呢。简单来说,quicklist编码是Redis3.2版本之后(包括当前版本)提供了一种新的内部编码。它和ziplist和linkedlist编码相比它结合了这两种编码的优势,具体的区别以后的文章中在做详细介绍。由于我电脑安装的Redis的版本是4.0.9,在3.2版本之后所以,上述代码执行后的内部编码为quicklist。
2.当元素个数超过512个元素时,内部编码将变为linkedlist。以下代码都是本人在Redis4.0.9中的测试,所以上述的验证本人没有验证成功。
import redis
r = redis.Redis(host='127.0.0.1', port=6379)
print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
for i in range(1,512):
r.rpush('listkey', i)
print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】
3.当列表中某个元素超过64个字节时,内部编码也会变成linkedlist。以下代码也是本人在Redis4.0.9中的测试,所以上述的验证本人也没有验证成功。
import redis
r = redis.Redis(host='127.0.0.1', port=6379)
print('Key为【listkey】的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
value = ''
for i in range(1,512):
value += str(i)
r.rpush('listkey', i)
print('Key为【listkey的字节编码为【%s】' % r.object('encoding', 'listkey').decode('utf-8'))
Key为【listkey】的字节编码为【quicklist】
Key为【listkey的字节编码为【quicklist】
上述内容就是Redis列表类型的相关知识,如有不正确的地方,欢迎指出,在下一篇中,我将分享Redis列表类型的使用场景。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。