一、简介
列表(list)类型是用来存储多个有序的字符串,如图2-18所示,a、b、c、d、e一个元素从左到右组成了一个有序的列表,列表中的每个字符串称为元素(element),一个列表最多可存储 2^32 - 1
个元素。在Redis中,可以对列表两端插入(push)和弹出(pop),还可以获取指定范围的元素列表、获取指定索引下标的元素等(如图2-18和图2-19所示)。列表是一种比较灵活的数据结构,它可以充当栈和队列的角色,在实际开发上有很多应用场景。
![](https://img.haomeiwen.com/i2021264/40e10059c04273de.png)
列表类型有两个特点:
- 列表中的元素是有序的,这就意味着可以通过索引下标获取某个元素或者某个范围内的元素列表。
- 列表中的元素可以是重复的。
二、命令
1、添加操作
1)从右边插入元素
rpush key value [value ...]
如:
127.0.0.1:6379> rpush mylist c b a
(integer) 3
lrange 0 -1
命令可以从左到右获取列表的所有元素:
127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "b"
3) "a"
2)从左边插入元素
lpush key value [value ...]
3)向某个元素的前或者后插入元素
linsert key before|after pivot value
linsert命令会从列表中找到等于pivot的元素,在其前(before)或者后(after)插入一个新的元素value,如:
127.0.0.1:6379> linsert mylist before b java
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "java"
3) "b"
4) "a"
2、查找
1)获取指定范围内的元素列表
lrange key start end
lrange操作会获取列表指定索引范围所有的元素。
索引下标有两个特点:
- 索引下标从左到右分别是0到N-1,但是从右到左分别是-1到-N。
- lrange中的end选项包含了自身,这个和很多编程语言不包含end不太相同。
例如想获取列表的第2到第4个元素,可以执行如下操作:
127.0.0.1:6379> lrange mylist 1 3
1) "java"
2) "b"
3) "a"
2)获取列表的所有元素
lrange key 0 -1
3)获取列表指定索引下标的元素
lindex key index
例如获取当前列表最后一个元素:
127.0.0.1:6379> lindex mylist -1
"a"
4)获取列表长度
llen key
如:
127.0.0.1:6379> llen mylist
(integer) 4
3、删除
1)从列表左侧弹出元素
lpop key
如:
127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "java"
3) "b"
4) "a"
127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> lrange mylist 0 -1
1) "java"
2) "b"
3) "a"
2)从列表右侧弹出元素
rpop key
用法和lpop
一样。
3)删除指定元素
lrem key count value
lrem命令会从列表中找到等于value的元素进行删除,根据count的不同分为三种情况:
- count>0,从左到右,删除最多count个元素。
- count<0,从右到左,删除最多count绝对值个元素。
- count=0,删除所有元素。
例如向列表从左向右插入5个a,那么当前列表变为“a a a a a java b a”,下面操作将从列表左边开始删除4个为a的元素:
127.0.0.1:6379> lpush mylist a a a a a
(integer) 8
127.0.0.1:6379> lrem mylist 4 a
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "java"
3) "b"
4) "a"
4)按照索引范围修剪列表
ltrim key start end
例如,下面操作会只保留列表mylist第2个到第4个元素:
127.0.0.1:6379> ltrim mylist 1 3
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "java"
2) "b"
3) "a"
4、修改
修改指定索引下标的元素:
lset key index newValue
如:
127.0.0.1:6379> lset mylist 2 python
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "java"
2) "b"
3) "python"
5、阻塞操作
阻塞式弹出如下:
blpop key [key ...] timeout
brpop key [key ...] timeout
blpop和brpop是lpop和rpop的阻塞版本,它们除了弹出方向不同,使用方法基本相同,所以下面以brpop命令进行说明,brpop命令包含两个参数:
- key [key ...]:多个列表的键。
- timeout:阻塞时间(单位:秒)
1)列表为空
如果timeout=3,那么客户端要等到3秒后返回,如果timeout=0,那么客户端一直阻塞等下去。
如:
127.0.0.1:6379> brpop list-test 3
(nil)
(3.04s)
127.0.0.1:6379> brpop list-test 0
...阻塞...
如果在阻塞期间添加了数据,那么客户端立即返回:
127.0.0.1:6379> brpop list-test 3
1) "list-test"
2) "val1"
(1.29s)
2)列表不为空
客户端会立即返回。
127.0.0.1:6379> lpush list-test val1
(integer) 1
127.0.0.1:6379> brpop list-test 3
1) "list-test"
2) "val1"
在使用brpop时,有两点需要注意。
- 第一点,如果是多个键,那么brpop会从左至右遍历,一旦有一个键能弹出元素,客户端立即返回:
127.0.0.1:6379> brpop list:1 list:2 list:3 0
...阻塞...
此时另一个客户端分别向list:2和list:3插入元素:
127.0.0.1:6379> lpush list:2 v2
(integer) 1
127.0.0.1:6379> lpush list:3 v3
(integer) 1
客户端会立即返回list:2中的v2,因为list:2最先有可弹出的元素:
127.0.0.1:6379> brpop list:1 list:2 list:3 0
1) "list:2"
2) "v2"
(9.88s)
- 第二点,如果多个客户端对同一个键执行brpop,那么最先执行brpop命令的客户端可以获取到弹出的值。
客户端1:
127.0.0.1:6379> brpop list:test 0
...阻塞...
客户端2:
127.0.0.1:6379> brpop list:test 0
...阻塞...
客户端3:
127.0.0.1:6379> brpop list:test 0
...阻塞...
此时另一个客户端lpush一个元素到list:test列表中:
127.0.0.1:6379> lpush list:test element
(integer) 1
那么客户端1最会获取到元素,因为客户端1最先执行brpop,而客户端2和客户端3继续阻塞。
客户端1:
127.0.0.1:6379> brpop list:test 0
1) "list:test"
2) "element"
(92.70s)
三、列表命令时间复杂度
操作类型 | 命令 | 时间复杂度 |
---|---|---|
添加 | 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 end | O(s+n),s是start偏移量,n是start到end的范围 |
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 end | O(n),n是要裁剪的元素总数 | |
修改 | lset key index newValue | O(n),n是索引的偏移量 |
阻塞操作 | blpop 、 brpop | O(1) |
参考:
《Redis开发与运维》 付磊 & 张益军
网友评论