Redis基础数据类型——列表类型

列表类型

list可以存储一个有序的字符串列表,一般用于在两端添加元素,并从两端获取数据,或获取列表中一个片段数据列。Redis使用双向链表实现列表,因此两端添加元素时间复杂度为O(1),因此两端添加元素性能较好;获取时,越接近两端的元素获取速度就越快。(因此获取两端有限长度的子列表,如获取首尾的10条记录,从一个千万级和一个百位级的列表获取速度是一样的)。

因为采用了双向链表实现,虽然首尾添加和读取数据很快,但是要根据索引查找一个元素性能较慢。和java的LinkedList类似,查找元素时,如查找一个确切位置123,则列表需要移动指针到指定位置,并读取数据,因此位置离头尾越远,则查找过程时间越长,相对应的性能越低,这里的例子时间复杂度为O(123),如果长度为n的列表,从一端查找元素,则最差为O(n)

列表类型最多可容纳2^32-1个元素。列表的值类型必须是字符串,不能再嵌套其他Redis类型,如散列、列表、集合等。

命令

向列表两端增加元素,使用的指令如下:
LPUSH key value [value ...]
RPUSH key value [value ...]

LPUSH指令用来向列表左边增加元素,返回值表示增加元素后列表的长度。当有多个值元素时,依次加入到列表。

LPUSH key v1 v2 v3
# 此时列表的元素为[v3, v2, v1]

RPUSH指令用来向列表右侧增加元素,和LPUSH类似,返回值为添加后的列表长度。

RPUSH key v4 v5
# 此时列表的元素为[v3, v2, v1, v4, v5]
从两端获取元素
LPOP key
RPOP key
BLPOP list1 list2... TIMEOUT
BRPOP list1 list2... TIMEOUT

LPOP指令从列表左侧取出第一个元素,取出意味着先移除,再返回。LPOP后,则原始列表的长度减少1

LPOP a
# "3"
# 此时列表的元素为[2, 1, 4, 5]

RPOP指令从列表右侧取出第一个元素,和LPOP指令类似,移除右侧第一个元素后,并返回,列表长度减少1

RPOP a
# "5"
# 此时列表元素为[2, 1, 4]

BLPOP指令从指定的列表(list1,list2支持多个列表)左侧弹出元素,当列表没有元素时,会阻塞列表直到TIMEOUT超时,TIMEOUT=0时会一直阻塞下去。

当列表为空时,返回nil(只有TIMEOUT非0时,到期后没有获取到数据,就返回nil),否则返回成对的数据,第一个元素为被弹出得列表key(list1),第二个元素为弹出的数据。

# 客户端1
BLPOP mylist 0
# 此时客户端阻塞,当客户端2放入数据后,立即弹出数据
1) "mylist"
2) "1"
(19.50s)
# 最后的时间标识阻塞开始知道弹出数据的时间
# 客户端2
PUSH mylist 1 2

BRPOP指令同BLPOP指令基本功能一致,只是弹出方向为列表右侧。

获取列表长度
LLEN key

LLEN指令可以查询一个列表的长度,当key不存在时返回0。Redis的设计,有记录列表长度的信息,因此读取列表长度,将会直接返回长度值,因此其时间负责读为O(1),性能较高。

LLEN ab #不存在
# (integer) 0
LLEN a
# (integer) 3
查询列表子集
LRANGE key start stop

LRANGE通常会比LPOP、RPOP更为常用,后者可能主要是作为栈、队列来使用,相对来说使用不是很频繁(队列采用MQ的可能性更大);Redis的队列作为热门条目、个人收藏列表等更为常见,其读取的操作跟多为子集列表;配合start和stop可以实现任意子集的读取,Redis的列表索引从0开始。

# 仍使用之前的a列表[2, 1, 4]
LRANGE a 0 1
# "2"   "1"

LRANGE在读取列表子集时,返回后,不会删除列表元素,在获取子集时,包含stop位置的元素,如上述指令中,stop=1,则会返回所谓位置1的元素。

startstop支持负值,当索引位置为负值时,表示从右侧开始返回,-1表示右侧第一个元素,-2表示右侧第二个元素,依次类推。

(当stop超过了列表长度,则实际的stop位置为右边第一个元素)

(如果start > stop,则返回空列表)

# 返回从左侧第一个元素开始,到右侧第一个元素,因此该指令返回列表的全部元素
LRANGE a 0 -1
# "2"   "1"   "4"
# stop=4超过了列表长度, 则会返回全部数据,到最右边元素为止
LRANGE a 0 4
# "2"   "1"   "4"
LRANGE a -1 -4
# start > stop,返回空列表
LRANGE a 2 1
(empty list or set)
LRANGE a -1 -2
(empty list or set)
删除列表指定元素
LREM key count value

LREM指令用于删除key列表中,指定的元素,会按照一定的方向(从左往右或从右往左),删除当前方向上,前count个值为value的元素。返回值为删除的元素个数。

count=0,删除列表中所有的value元素

count>0,从左向右,删除前count个值为value的元素

count<0,从右向左,删除前abs(count)个值为value的元素

LRANGE a 0 -1
# "1" "2" "1" "4" "1"
LREM a 2 1
# (integer) 2
LRANGE a 0 -1
# "2" "4" "1"
LREM a -2 1
# (integer) 1
LRANGE a 0 -1
# "2" "4"
LPUSH a 4
RPUSH a 4
LRANGE a 0 -1
# "4" "2" "4" "4"
LREM a 0 4
#(integer) 3
LRANGE a 0 -1
# "2"
获取指定索引的值
LINDEX key index

LINDEX指令用于返回key列表指定索引index位置的值。

index >= 0,从左边开始查找,索引从0开始

index < 0,从右边开始查找,最右侧第一个元素索引为-1

index超出列表长度,则返回空nil

LRANGE a 0 -1
# "1" "2" "3"
LINDEX a 1
# "2"
LINDEX a -2
# "2"
LINDEX a 3
# (nil)
设置指定索引的值
LSET key index value

LSET指令将key列表的index索引位置设置值为value

index >= 0,从左边开始,对指定索引位置设置为value

index < 0,从右边开始,对指定索引位置设置为value

index超出列表范围(无论是大于0还是小于0),均报错:超出索引范围

LRANGE a 0 -1
# "1" "2" "3"
LSET a 1 4
# OK
LRANGE a 0 -1
# "1" "4" "3"
LSET a -2 5
# OK
LRANGE a 0 -1
# "1" "5" "3"
LSET a 3 6
# (error) ERR index out of range
往列表中插入元素
LINSERT key BEFORE|AFTER pivot value

LINSERT指令,从左到右,找到值为pivot的元素,并将值value插入到pivot之前(BEFORE),或之后(AFTER);如果pivot在列表中有多个,则从左找到的第一个进行插入。

pivot元素存在于列表中,插入完成,返回插入后的列表长度

pivot不存在时,返回-1

key不存在时,返回0

如果要操作的key存在,且不是列表,则异常

LRANGE a 0 -1
# "1" "5" "3"
LINSERT a AFTER 5 4
# (integer) 4
LRANGE a 0 -1
# "1" "5" "4" "3"
LINSERT a BEFORE 5 4
# (integer) 5
LRANGE a 0 -1
# "1" "4" "5" "4" "3"
LINSERT a BEFORE 4 6  # 有多个4,从左边找到第一个4,进行插入操作
# (integer) 6
LRANGE a 0 -1
# "1" "6" "4" "5" "4" "3"
LINSERT a BEFORE 0 23   # 未找到0,返回-1
# (integer) -1
LINSERT aa BEFORE 1 1   # aa不存在,返回0
# (integer) 0
列表裁剪指令LTRIM
LTRIM key start stop

LTRIM指令对一个列表进行删除指定范围(startstop)之外的所有元素,最终保留为startstop之间的元素,包括startstop位置的元素。不在这个范围的元素都将被删除。

startstop取值从0开始到末尾,可以为负值,表示从右侧开始,-1为最右侧元素

start > stop时,将清空所有的元素

LRANGE a 0 -1
# "1" "6" "4" "5" "4" "3"
LTRIM a 1 4
# OK
LRANGE a 0 -1
# "6" "4" "5" "4"
LTRIM a -3 -2
# OK
LRANGE a 0 -1
# "4" "5"
LTRIM a 1 0
# OK
LRANGE a 0 -1
(empty list or set)
移动列表最后一个元素到新列表RPOPLPUSH
RPOPLPUSH source destionation

RPOPLPUSH指令,将从一个列表末尾(最右侧)弹出一个元素,并加入到目标列表的左侧;并返回该元素的值。这个过程是原子的。当源列表为空时,执行该指令,将不发生弹出和压入操作,返回空。

LRANGE a 0 -1
# "3" "2" "1"
RPOPLPUSH a b
# "1"
LRANGE a 0 -1
# "3" "2"
LRANGE b 0 -1
# "1"
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容