【redis】03list类型

时间:2022-01-18 16:54:21
list类型
redis的list类型是一个链表结构,他的主要功能是push、pop、获取一个范围的所有值等等一些操作,
咱们push什么意思,push是不是相当于咱们php里面的array_push,是向数组压入一个元素
吧,这里的push是向咱们的链表里面压入一个元素,pop是从咱们的链表中弹出一个元素,
同样,他同样可以获取到一个范围内的所有值,那么操作的过程当中呢,
key可以理解为链表的名称,
Redis的list类型其实就是一个每个子元素都是string类型的双向链表。
我们可以通过push、pop操作从链表的头部或者尾部添加元素,
这样呢,咱们的list既可以作为栈,又可以作为队列。
先说一下栈跟队列的一些特性,
栈是什么样的结构,栈相当于咱们的一个试管,当咱们往试管里面放元素的时候,比如说我放第一个元素
第一个元素首先回到咱们栈的头部,我再插入第二个元素,然后接着往上落,这个时候我要把栈里面的的
东西依次取出来,咱们放的时候是1->2->3,那我取的时候是不是得先取3啊,
先把3取出来,2才能出来,2出来1才能出来吧,那么栈有一个什么样的特性呢,
大家可以看到是不是先进后出,1最先进去的,然后1最后出来的,这是栈的特性,
 
再来看下队列,队列相当于是一个管道,队列的进和栈是一样的,然后我想把队列中的内容取出来,
然后我们可以从队列的头部取,进的时候是1->2->3,出的时候也是1->2->3,
这是咱们队列的概念,队列的特性,队列的特性是什么意思,先进先出,  而栈呢,是先进后出,
这是队列跟栈的两个特性,
redis的list类型呢是一个双向链表,我们可以通过push、pop操作从头部或者尾部,添加删除元素,
也就是说咱们可以从头部压入,可以从尾部压入,可以从头部弹出也可以从尾部弹出,
是这样一个意思吧,所以,从一个地方压入和弹出在这种情况下,咱们是不是栈,
从一个地方压入,从另一个地方弹出,这样的话是不是就是一个队列啊,
所以说咱们的list类型既可以作为栈,又可以作为队列,
说了这么多,咱们的list有什么操作呢,
lpush代表从咱们的列表里面从头部压入一个元素,
 
【redis】03list类型
lrange 0 -1 
0表示从头部开始第一个元素,-1表示从尾部开始第一个元素,
就表示我从mylist这个链表结构里面从第一个元素一直取到最后一个元素,
全不取出来,以次取出来,那我看,我们这样子取的话,是不是从头开始取,
那从头开始取,去的第一个元素毋容置疑,一定是hello,那么第二个元素取出来的是不是world啊
记住lpush是从list的头部添加一个元素,
每次登录服务器,在运行redis客户端前,先看看一下,redis服务器的6379端口是不是启动了,
netstat -tunpl | grep 6379
发现咱们是不是没有启动啊,咱们启动一下,
/usr/local/redis/bin/redis-server /user/local/redis/etc/redis.conf
启动完以后再看下一个6379端口,发现redis-server这个进程在监听着,
是不是已经启动成功,这个时候启动成功咱们进入客户端,
/user/local/redis/bin/redis-cli
进入咱们的客户端,
lpush list1 "hello"
(integer) 1
list1代表这个链表结构的名称吧,lpush代表从头压入,
lpush list1 "world"
(integer) 2
然后咱们开始往外取,取刚才是不是说了我们用的是lrange方法,
lrange list1 0 -1
1) "world"
2) "hello"
 
0 -1代表,从头取到尾部,
大家可以看到当我在lpush第一次的时候,这里是不是返回一个1,返回这个1,
代表咱们list1里面的一个元素,当我第二次lpush list1的时候,这里返回一个2代表什么意思,
代表向里面插入了第二个元素,也就是说他返回的是咱们list1里面的元素个数,
 
大家看咱们第一个取出来的是不是“world”啊,你先压入的hello,然后在压入的world吧,
最后进来的最先出去吧,这就是咱们的lpush,他就是从咱们list的头部压入一个元素,
有咱们的lpush,就有咱们rpush
rpush,代表从咱们list的尾部压入一个元素,也就是说咱们理解了lpush理解rpush也应该很好理解,
咱们再来看一下,我这里再来举一个例子,
比如我先从尾部压入一个元素,hello,比如说我再从尾部压入一个元素,world对吧,
然后我lrange的时候,咱们 0 -1
是不是也是从头开始取吧,0代表从头吧,从头开始取,取出来的第一个是谁啊,
是hello,第二个出来是world,
道理是不是刚才,咱们从头向尾压入是不是一样的啊, 但是你取的时候是不是从头开始取,
对吧,刚才咱们做的实验,从头压入从头出来,是不是类似于咱们的栈,
现在呢,咱们从尾部压入从头弹出,整个是一个队列吧,队列咱们先压入的hello吧,
咱们做一个实验啊,验证咱们的结果,
rpush lsit2 "lijie"
(integer) 1
rpush lsit2 "lampbrother"
(integer) 2
rpush从尾部压入,
这里同样会返回1和2啊,
好这个时候我往回取,
lrange list2 0 -1
1) "lijie"
2) "lampbrother"
是不是先进先出,首先出来的是不是lijie吧,然后在出来lampbrother
大家可以看到效果是不是一样的啊,先出来的是lijie再出来的是lampbrother,
这样子达到一个什么样的效果,是不是先进先出,也就是说这是一个队列,
 
lpush和rpush都是从list的两端,压入吧,
比如说我从头压入一个元素one,然后我再从头压入一个元素two,
比如说我现在想在one和two之间压入一个元素,你说我现在应该怎么办,
我们可以使用一个方法,前面的lpush跟现在的rpush都不行了吧,
lpush和rpush是不是只能从头尾两段,来往里面压入吧,但现在咱们是不是要压入one跟two中间,
也就是说应该压入到one的前面,two的后面,
咱们有一个方法叫做,linsert
 
【redis】03list类型
看这个例子,首先是从尾部压入了一个world
然后linsert mylist3 before "world" "hello"
在world前面压入一个hello元素,
这里是不是也一样,我们要在one前面压入一个three,
看一下linsert list3 before "one" "three"
lpush list3 "one"
(integer) 1
lpush list3 "two"
(integer) 2

首先我压入一个one,从头压入,然后我们再压入一个two,

这个时候咱们再来看一下
lrange list3 0 -1
1) "two"
2) "one"
取的时候是不是先出two,再出one
我现在想在one跟two之间压入一个three,那咱们来看一下,首先要用到咱们的linsert方法,
linsert list3 before one three
(integer) 3
这里返回3,代表我的list3里面已经有三个元素,表示压入成功,压入成功以后,咱们看一下他的顺序
对不对啊,
lrange list3 0 -1
1) "two"
2) "three"
3) "one"
看一下是不是压进来了,大家要切记一个方向,从尾到头为向上,也就是说冗员指向头的方向为前,
弥补咱们的lpush跟rpush
 
那么咱们有个方法叫lset,是将咱们list里面制定下标的元素替换掉,它类似于咱们php里面的数组,
$arr = array(1, 2, 3);
$arr[0] = 4;
大家都知道0下标代表1这个元素吧,好我给他从新赋值,赋值为4。
好这个时候我在打印出来数组是啥啊,是不是array(4, 2, 3);
也就是说把第一个元素是不是从新复制了啊,从新复制给4了吧,
同样咱们的lset道理是一样的,看咱们的例子,
【redis】03list类型
lpush首先向咱们的list压入一个元素,hello,然后把list的index为0的,改为world
相当于是做赋值操作,将下标为0的元素更改为一个值,更改为world,最终获取出来的值是world
lpush list5 one
(integer) 1
lpush list5 two
(integer) 2
lpush list5 three
(integer) 3

从头压入三个元素,

lrange list5 0 -1
1) "three"
2) "two"
3) "one"
然后从头取,也就是说three是下标为0的元素吧,从0开始去的嘛~
two是下标为1的元素,one代表下标为2的元素,
lset list5 1 four
OK
现在咱们把1改掉,更改成功以后,这里返回一个OK,代表更改成功,
这个时候咱们在lrange
lrange list5 0 -1
1) "three"
2) "four"
3) "one"
达到咱们的效果了,相当于跟咱们php的数组是相似的,
 
lrem从key对应的list中删除n个和value相同的元素。来看下举例,
【redis】03list类型
首先从尾部插入一个元素,
谁啊hello,然后从尾部又插入一个元素hello,好我当前取出来是不是两个hello,
这里使用lrem代表从咱们的list5中,删除一个和hello相同的值,
lpush list5 "one"
(integer) 4
lpush list5 "one"
(integer) 5
lpush list5 "one"
(integer) 6
连续插入三个one,然后查看下这个list里面都有什么,
lrange list5 0 -1
1) "one"
2) "one"
3) "one"
4) "three"
5) "four"
6) "one"
总共有4个one吧,
lrem list5 3 "one"
(integer) 3
大家看这里面现在是6个元素吧,我这里删除三个one
代表从list5里面删除三个跟one相同的元素,
删除三个以后这里返回一个值,叫做什么呢,返回一个3是不是,
lrem list5 1 "one"
(integer) 1
我再来删除一个,这里返回一个1,代表什么意思,我们先来看一下,
lrange list5 0 -1
1) "three"
2) "four"
最后剩下three跟four啦,是不是把所有的one都删除掉了,这里返回的数字是什么意思啊,
这里返回的数,代表你删除掉的数的个数,好我这里在lrem一下
lrem list5 1 "one"
(integer) 0
这里应该没有的,返回为0吧,代表没有删除成功吧,这是咱们的lrem
从key对应的list中删除n个和value相同的元素,
n<0 从尾部删除, n = 0全部删除,
 
下一个方法是咱们的ltrim
ltrim是包邮制定key的值范围内的数据,这里举了个例子
 
【redis】03list类型
他向mylist8里面插入一个one,从尾部插入,
然后又从尾部插入一个two,然后在们来保存mylist8里面的1到-1
什么意思啊,
表示从下标为1的开始,一直到-1是不是到最后,也就是说除了1 到 -1之间的元素,
ltrim会把其他元素都删除掉,
【redis】03list类型
这样子的话保留的是two 和 three,注意你这里写的是保留的,
除此之外把两段的东西全部删除掉,这是咱们的ltrim的以方法,
 
rpush list8 one
(integer) 1
rpush list8 one
(integer) 2
rpush list8 one
(integer) 3
rpush list8 one
(integer) 4
我是不是从尾部插入了四个元素,
lrange list8  0 -1
1) "one"
2) "two"
3) "three"
4) "four"
那我这个时候ltrim一下,
ltrim list8 1 2
OK
代表除了下标为1的和下标为2的,所有的元素全部删除掉,
把两段全部删除掉,保留我指定的范围吧,这里返回一个OK代表咱们trim成功,
代表咱们ltrim成功啊,这个时候再:
lrange list8 0 -1
1) "two"
2) "three"
最终的结果是不是剩下了two跟three,对吧是不是跟这个结果是一样的啊,
验证了咱们的ltrim方法吧,这是ltrim,记住你后面写的数字是你保留的范围,
是保留的范围不是删除的范围,
 
list类型还有一个方法叫做lpop,代表从list的头部删除一个元素,大家还记得php里面有个array_pop
吧,这个函数的意思是将数组的最后一个单元删除掉,
lpop也是从咱们的listl链表弹出元素,那好我前面加一个l代表从头弹出一个元素,并返回删除元素,
rpop代表从list的尾部删除元素,并返回删除的元素,
【redis】03list类型
这里返回一个hello,代表已经将hello弹出,弹出以后我们再来看mylist的元素,
从0到-1,剩下什么,剩下world了吧,,
rpush list10 one
(integer) 1
rpush list10 two
(integer) 2
rpush list10 three
(integer) 3
插入3个元素以后,
lrange list10 0 -1
1) "one"
2) "two"
3) "three"
插入三个元素之后,我让她从头弹出一个元素,我们是不是用lpop吧,
lpop list10
"one"
这里返回一个one代表从咱们的list10里面,弹出从头开始的第一个元素,
谁啊,把one弹出了吧,
lrange list10 0 -1
1) "two"
2) "three"
最终是不是只剩下two跟three,
那么顾名思义有lpop就有rpop,
lpop代表从头弹出,那么rpop是不是就代表从尾弹出啊,
rpop list10
"three"
lrange list10 0 -1
1) "two"
是不是只剩下two啦,
这分别是从咱们的链表结构的头部或者尾部弹出一个元素,
 
那么咱们学完lpop方法跟,rpop方法以及lpush方法以及rpush方法,
是不是都是相对立的,是吧要不从头要不从尾部,
从头或者尾压入,从头或者尾弹出,
rpoplpush是把两个方法放到一块儿啦,那么这样是不是比较好理解啊,
首先第一步干嘛,第一步从尾部弹出,然后呢第二步从头压入,
那好这个咱们能做什么,他的意思是,
从第一个list的尾部移除元素,是不是rpop做的,
然后并添加到咱们第二个list的头部,这是谁做的lpush做的吧,
【redis】03list类型
 
第一步rpop从muylist5弹出hello,第二步lpush到咱们的mylist6里面,
把hello从mylist5的尾部弹出,然后向mylist6的头压入,这是咱们rpop,lpush做的工作,
最终返回的结果是hello hello foo
rpush list11 three
(integer) 1
rpush list11 hello
(integer) 2
压入两个元素,然后来看一下咱们的list11,
lrange list11 0 -1
1) "three"
2) "hello"
rpush list12 hello
(integer) 1
rpush list11 foo
(integer) 2
压入两个元素,然后来看一下咱们的list12,
lrange list12 0 -1
1) "hello"
2) "foo"
rpoplpush list11 list12
"hello"
最终返回hello,是不是返回你弹出的这个hello啊,
来看成功压入list12啦没有啊,
lrange list12 0 -1
1) "hello"
2) "hello"
3) "foo"
最终结果是不是hello hello foo跟咱们这个结果是不是完全相同的吧,

list还有一个方法叫lindex

index不用说了索引吧,返回名称为key的list中index位置的元素,
【redis】03list类型
0 和 1代表的都是元素的索引,
 
lrange list12 0 -1
1) "hello"
2) "hello"
3) "foo"
list12中有三个元素,分别,的索引值是多少,0,1,2
lindex list12 2
"foo"
lindex list12 3
(nil)
空redis返回的nil,这是咱们的lindex代表取索引值的元素,
 
最后还有一个返回咱们key对应list的长度的方法,返回链表里面的元素个数,
llen list12
(integer) 3
返回值,代表的就是你这个链表里面有多少个元素,
相当于咱们php数组里面的count($a)
这就是咱们所有的list方法,