Redis数据结构详细解释之List,redis列表形式

往列表里存放数据先进后出(左进)

Redis数据类型之List类型

List类型(列表类型)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。

它的底层实际是个链表

  在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。
      从元素插入和删除的效率视角来看,如果我们是在链表的两头插入或删除元素,这将会是非常高效的操作,即使链表中已经存储了百万条记录,该操作也可以在常量时间内完成。然而需要说明的是,如果元素插入或删除操作是作用于链表中间,那将会是非常低效的。相信对于有良好数据结构基础的开发者而言,这一点并不难理解。

序言

思来想去感觉redis中的list没什么好写的,如果单写几个命令的操作过于乏味,所以本篇最后我会根据redis中list数据类型的特殊属性,同时对比成熟的消息队列产品rabbitmq,使用redis实现一个消息队列。 

为啦让本篇更有魅力,我再介绍下redis中list的基本属性,以及为什么使用redis中list列表类型,为什么使用消息队列,为什么不用rabbitmq而使用redis实现消息队列?呢,到这里为止,如果你是大咖,大牛,大神,大爷!不要听我吹牛逼啦,Close Page and forget me ! —_— 

lpush  names  A  B C D E

List(列表类型)常用命令

1、LPUSH key value1 [value2]

首先回答序言中的4大疑问 

1、redis中的list的基本属性?

List数据结构是链表结构,这意味这无论数据量多大,头尾操作数据还是很快的,list的容量是2的32次方减1个元素,即4294967295个元素数量。

2、为什么使用redis中的list数据类型?

依靠redis内存中操作数据的优势,又提供一些列实用独特的Api操控数据,用着简便,速度又快,又能实现特有的数据特征排序读写,做时间轴数据,评论列表,消息传递等等,又提供简便的分页,读写操作。你用不用。

3、为什么使用消息队列?

举个简单的例子,功能是这样子的,你要呈现页面给用户看,在你呈现页面之前有一个很复杂耗时的运算要操作,但是这个操作不影响页面呈现的数据,也不作为页面呈现的数据。 

方案一:运算完,呈现页面。

方案二:把要计算的数据,抛到持久化的消息队列中,不做耗时的运算,直接呈现页面。然后用另外一个程序来对消息队列中的数据单独做运算。 

显而易见,方案二是最佳答案,你用不用消息队列。

4、为什么不使用成熟的rabbitmq而使用redis实现的消息队列? 

Rabbitmq只关注数据的先进先出,没有数据优先级的概念,假如你想给那个数据来个先处理的特权,那么不好意思,我不支持,但是rabbitmq也可以变通着来处理,就是建立多个队列用程序路由来实现这个特权功能。那么redis实现的消息队列,是可以灵活掌控的,后面做示范。

 

创建列表

lpush左侧添加/rpush右侧添加

lpush从左侧添加

127.0.0.1:6379> lpush list01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"

rpush从左侧添加

127.0.0.1:6379> rpush list02 1 2 3 4 5
(integer) 5
127.0.0.1:6379> lrange list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

在列表头(左)加上一个或多个值的列表

Redis中关于List列表的命令详解 

1、redis中list列表的数据插入命令:lpush,rpush,linsert

127.0.0.1:6379>rpush mylist 1   ---结果为:(integer) 1

127.0.0.1:6379>rpush mylist 2   ---结果为:(integer) 2

127.0.0.1:6379>rpush mylist 3   ---rpush命令:向mylist列表中,从右边插入3条数据,返回值为当前列表的容量。结果为:(integer) 3

127.0.0.1:6379>lrange mylist 0 -1   ---lrange命令:查看mylist列表中的数据,0开始位置,-1结束位置,结束位置为-1时,表示列表的最后一个位置,即查看所有。结果为:1> "1"  2> "2"  3> "3"

127.0.0.1:6379>lpush mylist 0   ---lpush命令:向mylist列表中,从左边插入一条数据为0的数据

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"0"  2>"1"  3>"2"  4>"3"

127.0.0.1:6379>linsert mylist after 3 4   ---linsert命令,表达式为linsert key before|after pivot value ;这句命令的意思是在key为mylist的列表中查找值为3的数据,在其后插入一条值为4的数据。

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"0"  2>"1"  3>"2"  4>"3"  5>"4"

127.0.0.1:6379>linsert mylist before 0 -1   ---意思是:在key为mylist的列表中查找值为0的数据,在其前插入一条值为-1的数据。

127.0.0.1:6379>lrange mylist 0 -1    ---结果为:1>"-1"  2>"0"  3>"1"  4>"2"  5>"3"  6>"4"

127.0.0.1:6379>lisert mylist after 5 8    ---结果为:-1,由于mylist列表不存在值为5的数据,所以不执行任何操作,返回状态值-1。如果key不存在时,返回错误提示。

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"-1"  2>"0"  3>"1"  4>"2"  5>"3"  6>"4"

2、redis中list列表的数据删除命令:lpop,rpop

127.0.0.1:6379>lpop mylist    ---lpop命令:从列表中的左边移除一条数据,同时输出被删除的数据,这里输出的结果为-1

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"0"  2>"1"  3>"2"  4>"3"  5>"4"

127.0.0.1:6379>rpop mylist   ---rpop命令:从列表的右边移除一条数据,同时输出被删除的数据,这里输出的结果为4

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"0"  2>"1"  3>"2"  4>"3" 

127.0.0.1:6379>ltrim mylist 1 3   ----ltrim命令:保留设定的两个下标区间的值,删除不在其区间的所有值。1为开始保留的下标值,3为结束保留的下标值。

127.0.0.1:6379>lrange mylist 0 -1   ---结果为:1>"1"  2>"2"  3>"3" 

3、redis中list列表的数据查看命令:lrange,llen,lindex

127.0.0.1:6379>llen mylist   ---llen命令:返回列表的长度,这里mylist只剩下4条数据,故输出结果为4

127.0.0.1:6379>lindex mylist 3   ---lindex命令:获取给定位置的数据,这里坐标为3的数据是"2",所以结果为2.

4、redis中list列表数据修改命令:lset

127.0.0.1:6379>lset mylist 2 zlh   ---lset命令:把下标为2的值设置为zlh,如果下标值超出范围或对一个空list列表进行lset,那么将返回一个错误提示

127.0.0.1:6379>lrange mylist 0 -1   ---结果为: 1>"1"  2>"2"  3>"zlh"

5、redis中list列表,两个列表A,B,将A列表的尾元素添加到B列表的头元素中,命令:rpoplpush

#这里我有连个列表A数据为{1,2,3} ,B列表数据为{4,5,6}

127.0.0.1:6379>rpoplpush A B

127.0.0.1:6379>lrange A   ---结果为:1>"1' 2>"2"

127.0.0.1:6379>lrange B   ---结果为:1>"3' 2>"4" 3>"5" 4>"6"

6、redis中的几个带阻塞的高级命令:blpop,brpop,brpoplpush

127.0.0.1:6379>blpop A 30   ---意思是:A列表有值的话,从左边移除一个数据,如果没有值的话,则等待A中插入数据为止,等待时间为30秒,如果时间设置为0表示阻塞时间无限延长

127.0.0.1:6379>blpop B30   ---意思是:A列表有值的话,从左边移除一个数据,如果没有值的话,则等待A中插入数据为止,等待时间为30秒,如果时间设置为0表示阻塞时间无限延长

127.0.0.1:6379>brpoplpush A B 30   ---意思是:将A列表的尾元素添加到B列表的头元素中,如果A列表中有值则插入,如果没值,则等待A中插入数据为止,等待时间为30秒,如果时间设置为0表示阻塞时间无限延长

往列表里存放数据后进先出(右进)

查看List元素

  • lrange key start end start/end超出索引则忽略.
  • lrange key 0 -1 查看list全部元素.
  • lrange key 0 1 查看list 索引为0/1元素.
  • lrange key 0 length 1 查看list 0 - (length-1) 的元素,超出的索引忽略.
  • lrange key 1 3 查看list索引为1-3的元素.

lrange key start end

127.0.0.1:6379> lrange list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list02 0 3
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> lrange list02 0 4
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list02 0 5
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list02 0 6
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> lrange list02 6 9
(empty list or set)
127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "c"
2) "b"
3) "a"

Redis实现消息队列,并自带优先级功能

1、首先redis中的list是链表结构,具备消息队列中的先进先出特征。

2、从上面的几个高级命令中可以看出,list有几个自带阻塞功能,时间设置为0,可以视为永不休息的监听进程。

实现:

1、说啦以上两点我想你应该有想法啦。

2、对不起有点晚啦,明天还要上班,还要陪媳妇去吃个麻辣烫,回来睡觉啦,这里已经不难理解与实现啦,如需沟通交流学习,进左上角群,对不住啦,88,晚安。

rpush names  G P H K

弹出/取出list元素

lpop key(左侧弹出list元素)

127.0.0.1:6379> lpop list01
"5"
127.0.0.1:6379>  lrange list01 0 -1
1) "4"
2) "3"
3) "2"
4) "1"

rpop key(右侧弹出list元素)

127.0.0.1:6379> rpop list02
"5"
127.0.0.1:6379> lrange list02  0 -1
1) "1"
2) "2"
3) "3"
4) "4"

LPUSH 就是在左边插入,插入 a b c 就是先 a -> b a -> c b a 。

 

按照索引获取元素(从上到下)

lindex key index按照索引下标获得元素(从上到下)

127.0.0.1:6379> lindex list01 2
"2"
127.0.0.1:6379> lrange list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"

2、RPUSH key value1 [value2]

查看列表里面的数据:

获取List元素个数

llen key获取list元素个数

127.0.0.1:6379> lrange list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> llen list02
(integer) 4

在列表尾(右)加上一个或多个值的列表

lrange names 0(从0开始)  -1

删除N个value值

  • lrem key n value 如果没有n个value,有多少个删除多少个.
  • lrem key n value 从上到下按照顺序删除.

lrem key n

127.0.0.1:6379> lpush list03 1 1 1 2 2 2 3 3 3 4 4 4 4 5 3 4 4 5
(integer) 18
127.0.0.1:6379> llen list03
(integer) 18
127.0.0.1:6379> lrange list03 0 -1
 1) "5"
 2) "4"
 3) "4"
 4) "3"
 5) "5"
 6) "4"
 7) "4"
 8) "4"
 9) "4"
10) "3"
11) "3"
12) "3"
13) "2"
14) "2"
15) "2"
16) "1"
17) "1"
18) "1"
127.0.0.1:6379> lrem list03 4  3
(integer) 4
127.0.0.1:6379> lrange list03 0 -1
 1) "5"
 2) "4"
 3) "4"
 4) "5"
 5) "4"
 6) "4"
 7) "4"
 8) "4"
 9) "2"
10) "2"
11) "2"
12) "1"
13) "1"
14) "1"
127.0.0.1:6379> lrem list03 3 5
(integer) 2
127.0.0.1:6379> lrange list03 0 -1
 1) "4"
 2) "4"
 3) "4"
 4) "4"
 5) "4"
 6) "4"
 7) "2"
 8) "2"
 9) "2"
10) "1"
11) "1"
12) "1"
127.0.0.1:6379> rpush mylist a b c 
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"

切片:

截取list元素并且赋值给list

  • ltrim key start end 把 start end中的元素赋值给key
  • ltrim key start end 是包含 start end 元素
  • ltrim key start end 如果索引超出范围,则自动忽略.

ltrim key start end

127.0.0.1:6379> lpush list04 1 2 3 4 5 6 7 8 9 0
(integer) 10
127.0.0.1:6379> lrange list04 0 -1
 1) "0"
 2) "9"
 3) "8"
 4) "7"
 5) "6"
 6) "5"
 7) "4"
 8) "3"
 9) "2"
10) "1"
127.0.0.1:6379> ltrim list04 3 5
OK
127.0.0.1:6379> lrange list04 0 -1
1) "7"
2) "6"
3) "5"
127.0.0.1:6379> ltrim list04 0 7
OK
127.0.0.1:6379> lrange list04 0 -1
1) "7"
2) "6"
3) "5"

RPUSH 就是在右边插入,插入 a b c 就是先 a -> a b -> a b c

lrange names  start  end(start end 代表开始和结束位置)

在list元素前后添加新元素

  • linsert key before/after value new_value 在value值前后添加new_value
  • 从上到下找到第一个匹配
  • 找不到则value 这返回-1 不作操作.

linsert key value new_value

127.0.0.1:6379> lpush list05 x i a o m i
(integer) 6
127.0.0.1:6379> lrange list05 0 -1
1) "i"
2) "m"
3) "o"
4) "a"
5) "i"
6) "x"
127.0.0.1:6379> linsert list05 before i 1
(integer) 7
127.0.0.1:6379> linsert list05 after i 2
(integer) 8
127.0.0.1:6379> lrange list05 0 -1
1) "1"
2) "i"
3) "2"
4) "m"
5) "o"
6) "a"
7) "i"
8) "x"
127.0.0.1:6379> linsert list05 after v  100
(integer) -1

3、LPOP key

 

性能特点

  1. 它是一个字符串链表,left、right都可以插入添加;
  2. 如果键不存在,创建新的链表;
  3. 如果键已存在,新增内容;
  4. 如果值全移除,对应的键也就消失了。
  5. 链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

获取并取出列表中的第一个元素(左边第一个)

插入:

127.0.0.1:6379> rpush mylist a b c 
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> lpop mylist
"a"
127.0.0.1:6379> lpop mylist
"b"
127.0.0.1:6379> lpop mylist
"c"

linsert names  BEFORE/AFTER  D(标杆就是插到哪里)  TEST

4、RPOP key

修改:

取出并获取列表中的最后一个元素(右边第一个)

lset names 3 xiaopang

127.0.0.1:6379> rpush mylist a b c 
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> rpop mylist
"c"
127.0.0.1:6379> rpop mylist
"b"
127.0.0.1:6379> rpop mylist
"a"

删除:

5、LLEN key

lrem name 3 xiaopang

获取列表的长度

 

127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> llen mylist
(integer) 3
127.0.0.1:6379> rpush mylist d
(integer) 4
127.0.0.1:6379> llen mylist
(integer) 4

从列表左侧移除:

6、LRANGE key start stop 

lpop names

从一个列表获取元素,其中start/stop都是下标,并且都可以是负数,比如-1表示倒数第一个,-2表示倒数第二个。

 

127.0.0.1:6379> rpush mylist a b c 
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"

除下标1-2其他数据都移除:

7、LTRIM key start stop

LTRIM names 1 2(下标位置)

修剪列表到指定的范围内

 

127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> ltrim mylist 1 -1
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "b"
2) "c"
3) "d"

names最后一个数据,插入到names2的第一个位置:

这里的 start/stop 也是下标,也可以是负数。

RPOPLPUSH  names  names2

8、LREM key count value

 

根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。

删除列表数据:

COUNT 的值可以是以下几种:

BLPOP  names 4(没有数据就等4秒,有数据就会显示,等待的时候可以继续往里放数据)

  • count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
  • count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
  • count = 0 : 移除表中所有与 VALUE 相等的值。

    127.0.0.1:6379> lrange mylist 0 -1 1) "a" 2) "b" 3) "c" 4) "a" 5) "a" 6) "d" 7) "e" 127.0.0.1:6379> lrem mylist 2 a (integer) 2 127.0.0.1:6379> lrange mylist 0 -1 1) "b" 2) "c" 3) "a" 4) "d" 5) "e"

 

上面的命令指示:在 mylist 列表,从左到右扫描,移除两个与 'a' 相等的值。

 把names里的最后一个数据,放到names2的第一个位置:

6、LINSERT key BEFORE|AFTER pivot value

BRPOPLPUSH names names2 40

在列表中的其他元素之后或之前插入一个元素

127.0.0.1:6379> rpush list1 foo
(integer) 1
127.0.0.1:6379> rpush list1 bar
(integer) 2
127.0.0.1:6379> linsert list1 before bar yes
(integer) 3
127.0.0.1:6379> lrange list1 0 -1
1) "foo"
2) "yes"
3) "bar"

8、LINDEX key index

从一个列表其索引获取对应的元素

127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> lindex mylist 0
"a"
127.0.0.1:6379> lindex mylist 3
"d"

9、LSET key index value

在列表中的索引设置一个元素的值

127.0.0.1:6379> lrange mylist 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
127.0.0.1:6379> lset mylist 0 aa
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "aa"
2) "b"
3) "c"
4) "d"

 

 

 

====================== 我是罪恶的分割线 ======================

RPOPLPUSH source destination

删除最后一个元素的列表,将其附加到另一个列表并返回它

BRPOPLPUSH source destination timeout

从列表中弹出一个值,它推到另一个列表并返回它;或阻塞,直到有可用

 

BLPOP key1 [key2] timeout

取出并获取列表中的第一个元素,或阻塞,直到有可用

BRPOP key1 [key2] timeout

取出并获取列表中的最后一个元素,或阻塞,直到有可用

 

LPUSHX key value

在前面加上一个值列表,仅当列表中存在

 

本文由星彩网app下载发布于计算机编程,转载请注明出处:Redis数据结构详细解释之List,redis列表形式

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。