Redis 基础 -- 列表 List 类型 和 List 类型的常用命令

Posted CodeJiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis 基础 -- 列表 List 类型 和 List 类型的常用命令相关的知识,希望对你有一定的参考价值。

文章目录

1. 列表(List)

Redis的列表(list)是一种线性的有序结构,可以按照元素被推入列表中的顺序来存储元素,这些元素既可以是文字数据,又可以是二进制数据,并且列表中的元素可以重复出现。

下图展示了一个包含多个字符串的列表,这个列表按照从左到右的方式,依次存储了"one"、“two”、“three”、"four"这4个元素。


1.1 LPUSH:将元素推入列表左端

用户可以通过LPUSH命令,将一个或多个元素推入给定列表的左端。

语法:


在推入操作执行完毕之后,LPUSH命令会返回列表当前包含的元素数量作为返回值。

示例:


说明:

复杂度:O(N),其中N为被推入列表的元素数量。


1.2 RPUSH:将元素推入列表右端

RPUSH命令和LPUSH命令类似,这两个命令执行的都是元素推入操作,唯一区别就在于LPUSH命令会将元素推入列表左端,而RPUSH命令会将元素推入列表右端。

语法:


在推入操作执行完毕之后,RPUSH命令会返回列表当前包含的元素数量作为返回值。

示例:

说明:

复杂度:O(N),其中N为被推入列表的元素数量。


1.3 LPUSHX、RPUSHX:只对已存在的列表执行推入操作

当用户调用LPUSH命令或RPUSH命令尝试将元素推入列表的时候,如果给定的列表并不存在,那么命令将自动创建一个空列表,并将元素推入刚刚创建的列表中。

除了LPUSH命令和RPUSH命令之外,Redis还提供了LPUSHX命令和RPUSHX命令。这两个命令对待空列表的方式与LPUSH命令和RPUSH命令正好相反:

  • LPUSHX命令只会在列表已经存在的情况下,将元素推入列表左端
  • RPUSHX命令只会在列表已经存在的情况下,将元素推入列表右端。

语法:

LPUSHX
RPUSHX

如果给定列表并不存在,那么LPUSHX命令和RPUSHX命令将放弃执行推入操作。LPUSHX命令和RPUSHX命令在成功执行推入操作之后,将返回列表当前的长度作为返回值,如果推入操作未能成功执行,那么命令将返回0作为结果。

示例:

演示RPUSHX,LPUSHX同理:


说明:

复杂度:O(N),其中N为被推入列表的元素数量。


1.4 LPOP:弹出列表最左端的元素

用户可以通过LPOP命令移除位于列表最左端的元素,并将被移除的元素返回给用户。

语法:

示例:

说明:

复杂度:O(N),其中N为弹出的元素数量。


1.5 RPOP:弹出列表最右端的元素

用户可以通过RPOP命令移除位于列表最右端的元素,并将被移除的元素返回给用户。

语法:

示例:

参考LPOP,这里不做演示了。

说明:

复杂度:O(N),其中N为弹出的元素数量。


1.6 RPOPLPUSH:将右端弹出的元素推入左端

RPOPLPUSH命令的行为和它的名字一样,首先使用RPOP命令将源列表最右端的元素弹出,然后使用LPUSH命令将被弹出的元素推入目标列表左端,使之成为目标列表的最左端元素。


语法:

RPOPLPUSH命令会返回被弹出的元素作为结果。

示例:

以下代码展示了如何使用RPOPLPUSH命令,将列表list1的最右端元素弹出,然后将其推入列表list2的左端:

下图展示了列表list1和list2在执行以上RPOPLPUSH命令时的变化过程:


1.6.1 源列表和目标列表相同

RPOPLPUSH命令允许用户将源列表和目标列表设置为同一个列表,在这种情况下,RPOPLPUSH命令的效果相当于将列表最右端的元素变成列表最左端的元素。

以下代码展示了如何通过RPOPLPUSH命令将rotate-list列表的最右端元素变成列表的最左端元素:

下图展示了以上3个RPOPLPUSH命令在执行时,rotate-list列表的整个变化过程:

可见,当我们对一个包含了N个元素的列表重复执行N次RPOPLPUSH命令之后,列表元素的排列顺序将变回原来的样子。


1.6.2 处理空列表

如果用户传给RPOPLPUSH命令的源列表并不存在,那么RPOPLPUSH命令将放弃执行弹出和推入操作,只返回一个空值表示命令执行失败:

如果源列表非空,但是目标列表为空,那么RPOPLPUSH命令将正常执行弹出操作和推入操作:

下图展示了这条RPOPLPUSH命令执行之前和执行之后,list-x和list-y的变化:


1.6.3 说明

复杂度:O(1)。


1.7 LLEN:获取列表的长度

用户可以通过执行LLEN命令来获取列表的长度,即列表包含的元素数量。

语法:

对于不存在的列表,LLEN命令将返回0作为结果。

示例:


说明:

复杂度:O(1)。


1.8 LINDEX:获取指定索引上的元素

Redis列表包含的每个元素都有与之对应的正数索引和负数索引:

  • 正数索引从列表的左端开始计算,依次向右端递增:最左端元素的索引为0,左端排行第二的元素索引为1,左端排行第三的元素索引为2,以此类推。最大的正数索引为列表长度减1,即N-1。
  • 负数索引从列表的右端开始计算,依次向左端递减:最右端元素的索引为-1,右端排行第二的元素索引为-2,右端排行第三的元素索引为-3,以此类推。最大的负数索引为列表长度的负数,即-N。

下图展示了一个包含多个元素的列表,并给出了列表元素对应的正数索引和负数索引。

为了让用户可以方便地取得索引对应的元素,Redis提供了LINDEX命令,这个命令接受一个列表和一个索引作为参数,然后返回列表在给定索引上的元素;其中给定索引既可以是正数,也可以是负数。

语法:

对于一个长度为N的非空列表来说:

  • 它的正数索引必然大于等于0,并且小于等于N-1。
  • 它的负数索引必然小于等于-1,并且大于等于-N。

如果用户给定的索引超出了这一范围,那么LINDEX命令将返回nil。

示例:

对于list1来说,他的索引情况为:

说明:

复杂度:O(N),其中N为给定列表的长度。


1.9 LRANGE:获取指定索引范围上的元素

用户除了可以使用LINDEX命令获取给定索引上的单个元素之外,还可以使用LRANGE命令获取给定索引范围上的多个元素。

语法:


RANGE命令接受一个列表、一个开始索引和一个结束索引作为参数,然后依次返回列表从开始索引到结束索引范围内的所有元素,其中开始索引和结束索引对应的元素也会被包含在命令返回的元素当中。

示例:



1.9.1 获取列表包含的所有元素

一个快捷地获取列表包含的所有元素的方法,就是使用0作为起始索引、-1作为结束索引去调用LRANGE命令,这种方法非常适合于查看长度较短的列表:


1.9.2 处理超出范围的索引

与LINDEX一样,LRANGE命令也需要处理超出范围的索引:

  • 如果用户给定的起始索引和结束索引都超出了范围,那么LRANGE命令将返回空列表作为结果。

  • 如果用户给定的其中一个索引超出了范围,那么LRANGE命令将对超出范围的索引进行修正,然后再执行实际的范围获取操作;其中超出范围的起始索引会被修正为0,而超出范围的结束索引则会被修正为-1。


1.9.3 说明

复杂度:O(N),其中N为给定列表的长度。


1.10 LSET:为指定索引设置新元素

用户可以通过LSET命令,为列表的指定索引设置新元素。

语法:

LSET命令在设置成功时将返回OK。

因为LSET命令只能对列表中已存在的索引进行设置,所以如果用户给定的索引超出了列表的有效索引范围,那么LSET命令将返回一个错误:

示例:

对于以下这个todo列表来说:
我们可以通过执行以下LSET命令,将todo列表索引1上的元素设置为"havelunch":

说明:

复杂度:O(N),其中N为给定列表的长度。


1.11 LINSERT:将元素插入列表

通过使用LINSERT命令,用户可以将一个新元素插入列表某个指定元素的前面或者后面。

语法:

示例:

对于lst列表:
我们可以通过执行以下LINSERT命令,将元素"10086"插入元素"b"的前面:
也可以通过执行以下LINSERT命令,将元素"12345"插入元素"c"的前面:

还可以通过执行以下LINSERT命令,将元素"6789"插入元素"c"的前面:

如果用户给定的目标元素并不存在,那么LINSERT命令将返回-1表示插入失败:

说明:

复杂度:O(N),其中N为给定列表的长度。


1.12 LTRIM:修剪列表

LTRIM命令接受一个列表和一个索引范围作为参数,并移除列表中位于给定索引范围之外的所有元素,只保留给定范围之内的元素。

语法:


LTRIM命令在执行完移除操作之后将返回OK作为结果。

示例:

对于以下这个alphabets列表来说:

执行以下命令可以让列表只保留索引0到索引6范围内的7个元素:

与LRANGE命令一样,LTRIM命令不仅可以处理正数索引,还可以处理负数索引。以下代码展示了如何通过给定负数索引,让LTRIM命令只保留列表的最后5个元素:

说明:

复杂度:O(N),其中N为给定列表的长度。


1.13 LREM:从列表中移除指定元素

用户可以通过LREM命令移除列表中的指定元素。

语法:

count参数的值决定了LREM命令移除元素的方式:

  • 如果count参数的值等于0,那么LREM命令将移除列表中包含的所有指定元素。
  • 如果count参数的值大于0,那么LREM命令将从列表的左端开始向右进行检查,并移除最先发现的count个指定元素。
  • 如果count参数的值小于0,那么LREM命令将从列表的右端开始向左进行检查,并移除最先发现的count的绝对值个指定元素。

LREM命令在执行完毕之后将返回被移除的元素数量作为命令的返回值。

示例:

对于以下3个包含相同元素的列表来说:
执行以下命令将移除sample1列表包含的所有"a"元素:

而执行以下命令将移除sample2列表最靠近列表左端的2个"a"元素:

因为上面的LREM命令只要求移除最先发现的2个"a"元素,所以位于列表最右端的"a"元素并没有被移除,下图展示了这个LREM命令的执行过程。

最后,执行以下命令将移除sample3列表最靠近列表右端的2个"a"元素:

因为上面的LREM调用只要求移除最先发现的2个"a"元素,所以位于列表最左端的"a"元素并没有被移除,下图展示了这个LREM调用的执行过程。

说明:

复杂度:O(N),其中N为给定列表的长度。


1.14 BLPOP:阻塞式左端弹出操作

BLPOP命令是带有阻塞功能的左端弹出操作,它接受任意多个列表以及一个秒级精度的超时时限作为参数。

BLPOP命令会按照从左到右的顺序依次检查用户给定的列表,并对最先遇到的非空列表执行左端元素弹出操作。如果BLPOP命令在检查了用户给定的所有列表之后都没有发现可以执行弹出操作的非空列表,那么它将阻塞执行该命令的客户端并开始等待,直到某个给定列表变为非空,又或者等待时间超出给定时限为止。

语法:

当BLPOP命令成功对某个非空列表执行了弹出操作之后,它将向用户返回一个包含两个元素的数组:数组的第一个元素记录了执行弹出操作的列表,即被弹出元素的来源列表,而数组的第二个元素则是被弹出元素本身。

示例:

在以下这个BLPOP命令执行示例中,被弹出的元素"a"就来源于列表alphabets:


1.4.1 解除阻塞状态

当BLPOP命令发现用户给定的所有列表都为空时,就会让执行命令的客户端进入阻塞状态。如果在客户端被阻塞的过程中,有另一个客户端向导致阻塞的列表推入了新的元素,那么该列表就会变为非空,而被阻塞的客户端也会随着BLPOP命令成功弹出列表元素而重新回到非阻塞状态。


1.4.2 处理空列表

如果用户向BLPOP命令传入的所有列表都是空列表,并且这些列表在给定的时限之内一直没有变成非空列表,那么BLPOP命令将在给定时限到达之后向客户端返回一个空值,表示没有任何元素被弹出:


1.4.3 列表名的作用

BLPOP命令之所以会返回被弹出元素的来源列表,是为了让用户在传入多个列表的情况下,知道被弹出的元素来源于哪个列表。

比如在以下这个示例中,通过BLPOP命令的回复,我们可以知道被弹出的元素来自于列表queue2,而不是queue1或者queue3:


1.4.4 阻塞效果的范围

BLPOP命令的阻塞效果只对执行这个命令的客户端有效,其他客户端以及Redis服务器本身并不会因为这个命令而被阻塞。


1.4.5 说明

复杂度:O(N),其中N为用户给定的列表数量。


1.15 BRPOP:阻塞式右端弹出操作

BRPOP命令是带有阻塞功能的右端弹出操作,除了弹出的方向不同之外,其他方面都和BLPOP命令一样。

语法:

说明:

复杂度:O(N),其中N为用户给定的列表数量。


1.16 BRPOPLPUSH:阻塞式弹出并推入操作

BRPOPLPUSH命令是RPOPLPUSH命令的阻塞版本,BRPOPLPUSH命令接受一个源列表、一个目标列表以及一个秒级精度的超时时限作为参数。

语法:

根据源列表是否为空,BRPOPLPUSH命令会产生以下两种行为:

  • 如果源列表非空,那么BRPOPLPUSH命令的行为就和RPOPLPUSH命令的行为一样,BRPOPLPUSH命令会弹出位于源列表最右端的元素,并将该元素推入目标列表的左端,最后向客户端返回被推入的元素。
  • 如果源列表为空,那么BRPOPLPUSH命令将阻塞执行该命令的客户端,然后在给定的时限内等待可弹出的元素出现,或者等待时间超过给定时限为止。

示例:

假设现在有list3、list4两个列表:

如果我们以这两个列表作为输入执行BRPOPLPUSH命令,由于源列表list3非空,所以BRPOPLPUSH命令将不阻塞直接执行,就像RPOPLPUSH命令一样:

现在,由于list3为空,如果我们再次执行相同的BRPOPLPUSH命令,那么客户端client-1将被阻塞,直到我们从另一个客户端client-2向list3推入新元素为止。

如果源列表在用户给定的时限内一直没有元素可供弹出,那么BRPOPLPUSH命令将向客户端返回一个空值,以此来表示此次操作没有弹出和推入任何元素:


与BLPOP命令和BRPOP命令一样,redis-cli客户端也会显示BRPOPLPUSH命令的阻塞时长。

说明:

复杂度:O(1)。


1.17 重点回顾

  • Redis的列表是一种线性的有序结构,可以按照元素推入列表中的顺序来存储元素,并且列表中的元素可以重复出现。
  • 用户可以使用LPUSH、RPUSH、RPOP、LPOP等多个命令,从列表的两端推入或者弹出元素,也可以通过LINSERT命令将新元素插入列表已有元素的前面或后面。
  • 用户可以使用LREM命令从列表中移除指定的元素,或者直接使用LTRIM命令对列表进行修剪。
  • 当用户传给LRANGE命令的索引范围超出了列表的有效索引范围时,LRANGE命令将对传入的索引范围进行修正,并根据修正后的索引范围来获取列表元素。
  • BLPOP、BRPOP和BRPOPLPUSH是阻塞版本的弹出和推入命令,如果用户给定的所有列表都为空,那么执行命令的客户端将被阻塞,直到给定的阻塞时限到达或者某个给定列表非空为止。


以上是关于Redis 基础 -- 列表 List 类型 和 List 类型的常用命令的主要内容,如果未能解决你的问题,请参考以下文章

记录Redis 基础

缓存数据库-redis数据类型和操作(list)

Redis学习基础二

redis的数据类型List,其原生命令和php操作Redis List函数介绍

Redis 基础数据结构之二 list(列表)

面试基础-redis