1. 什么是列表
redis的列表使用双向链表实现,往列表中放元素的时候复杂度是O(1),但是随机访问的时候速度就不行了,因为需要先遍历到指定的位置才可以取到元素。
既然列表是使用链表实现的,那么就说明它是有序的,元素按照放入的顺序排列。
列表支持从两端放元素或者取元素,这样的话就可以使用列表实现栈或者队列,如果只从队列的左边或者只从队列的右边取和放数据的话,列表就成了一个栈,如果从列表的左边取数据,右边放数据,或者从右边放数据,从左边取数据的话,列表就成了队列,列表比较常用的就是用来做队列。
2. 基本使用
放元素
放元素的时候可以从左边往里放,也可以从右边往里放,分别对应着lpush和rpush:
lpush <key> <value> [<value> …] rpush <key> <value> [<value> …]
放置元素的时候返回值是放置之后列表中元素的个数。
放置元素的时候可以一次放多个,可以看做是支持一种批量操作。
取元素
同理,取元素的时候可以从左边取,也可以从右边取,分别对应着lpop、rpop:
lpop <key> rpop <key>
取元素的时候返回值是取到的元素,如果列表是空的或者列表不存在的话返回值就是nil。
按下标访问和赋值
既然是列表,就可以按照下标方式访问。
lindex <key> <index> lset <key> <index> <value>
往列表中放元素的时候需要不能超过列表当前的长度,不然就越界了。
向列表中插入元素
linsert <key> before|after pivot value
会首先从列表中查找值为pivot的元素,然后来把value放在它的before或after。
因为列表是使用双向链表实现的,所以插入元素的时候只需要修改头尾的指向就可以了,无需移动元素。
删除列表元素,只保留指定区间的元素
ltrim <key> <start> <stop>
ltrim用来删除指定列表中指定区间之外的元素,只保留指定区间的元素。
通常使用ltrim来限制列表的大小,比如做一个功能只需要取前N个的时候可以使用ltrim删除掉索引100之后的元素.
获取列表长度
llen <key>
当列表为空或者不存在的时候返回值都是0.
取列表长度的复杂度为O(1),因为redis会维护一个值表示列表的长度,当使用llen命令的时候直接返回这个值就可以了。
取子列表
lrange <key> <start> <stop>
取子列表可以看做是java中的subList(),只是redis的取子列表的时候越界也没关系的,另外比较奇葩的是redis的子列表是包含头和尾的,在编写程序的时候说一个区间的时候一般的都是只包含头不包含尾。
元素的索引从0开始,并且取子列表并不会将元素从原列表中去除,而是会生成一个新的列表返回。
结束索引可以为负,当结束索引为负的时候表示从结束位置是从列表的最右边往左数abs(stop)个,比如有这么一个列表:
表示取从左边数第二个到从右边数第二个之间的数,并且是包含头和尾的。
当只想查看列表中有哪些元素但是并不想把这些元素移除的时候,比如使用列表做了一个队列,现在想看下这个队列中都有哪些元素但是并不想对原有的东西有啥影响,可以使用lrange <list> 0 -1来取列表中的所有元素:
删除元素
lrem <key> <count> <value>
删除列表中前count个值为value的元素。
根据count值得不同,执行方式有所不同:
count>0 从左边开始,删除count个值为value的元素
count=0 删除所有值为value的元素
count<0 从右边开始,删除abs(count)个值为value的元素
lrem的返回值是被删除的元素的个数。
列表之间转移元素
rpoplpush <source> <destination>
这个命令会先对source列表指定rpop弹出一个元素,然后对destination列表指定lpush把刚刚那个元素放进去,这是一个原子操作。
参考资料:
1. 《redis入门指南》 第二版
.