2.7 Set集合
Redis的集合相当于Java语⾔⾥⾯的HashSet,它内部的键值对是⽆序的唯⼀的。它的内部实现相当于⼀个特殊的字典,字典中所有的value都是⼀个值NULL。当集合中最后⼀个元素移除之后,数据结构⾃动删除,内存被回收。
插入之后,元素的先后位置是不固定的,遍历的时候无序。
下面我们看一下它的API
1.SADD¶
SADD key member [member …]
时间复杂度: O(N), N 是被添加的元素的数量。
将一个或多个member元素加入到集合key当中,已经存在于集合的member元素将被忽略。假如key不存在,则创建一个只包含member元素作成员的集合。当key不是集合类型时,返回一个错误。正常返回被添加到集合中的新元素的数量,不包括被忽略的元素。
# 添加单个元素 redis> SADD bbs "discuz.net" (integer) 1 # 添加重复元素 redis> SADD bbs "discuz.net" (integer) 0 # 添加多个元素 redis> SADD bbs "tianya.cn" "groups.google.com" (integer) 2 redis> SMEMBERS bbs 1) "discuz.net" 2) "groups.google.com" 3) "tianya.cn"
2.SCARD¶
SCARD key
时间复杂度:O(1) 返回集合key的基数(集合中元素的数量)。当key不存在时,返回0。
redis> SADD tool pc printer phone (integer) 3 redis> SCARD tool # 非空集合 (integer) 3 redis> DEL tool (integer) 1 redis> SCARD tool # 空集合 (integer) 0
3.SMEMBERS¶
SMEMBERS key
时间复杂度:O(N),N为集合的基数。返回集合key中的所有成员。不存在的key被视为空集合。
# key 不存在或集合为空 redis> EXISTS not_exists_key (integer) 0 redis> SMEMBERS not_exists_key (empty list or set) # 非空集合 redis> SADD language Ruby Python Clojure (integer) 3 redis> SMEMBERS language 1) "Python" 2) "Ruby" 3) "Clojure"
可以看出来,插入顺序,与返回顺序不同。要小心使用
4.srandmember和spop¶
SRANDMEMBER key [count]
时间复杂度:只提供key参数时为O(1。如果提供了count参数,那么为O(N),N为返回数组的元素个数。
如果命令执行时,只提供了key参数,那么返回集合中的一个随机元素。从Redis 2.6 版本开始,SRANDMEMBER命令接受可选的count参数:
- 如果count为正数,且小于集合基数,那么命令返回一个包含count个元素的数组,数组中的元素各不相同。如果count大于等于集合基数,那么返回整个集合。
- 如果count为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为count的绝对值。
# 添加元素 redis> SADD fruit apple banana cherry (integer) 3 # 只给定 key 参数,返回一个随机元素 redis> SRANDMEMBER fruit "cherry" redis> SRANDMEMBER fruit "apple" # 给定 3 为 count 参数,返回 3 个随机元素 # 每个随机元素都不相同 redis> SRANDMEMBER fruit 3 1) "apple" 2) "banana" 3) "cherry" # 给定 -3 为 count 参数,返回 3 个随机元素 # 元素可能会重复出现多次 redis> SRANDMEMBER fruit -3 1) "banana" 2) "cherry" 3) "apple" redis> SRANDMEMBER fruit -3 1) "apple" 2) "apple" 3) "cherry" # 如果 count 是整数,且大于等于集合基数,那么返回整个集合 redis> SRANDMEMBER fruit 10 1) "apple" 2) "banana" 3) "cherry" # 如果 count 是负数,且 count 的绝对值大于集合的基数 # 那么返回的数组的长度为 count 的绝对值 redis> SRANDMEMBER fruit -10 1) "banana" 2) "apple" 3) "banana" 4) "cherry" 5) "apple" 6) "apple" 7) "cherry" 8) "apple" 9) "apple" 10) "banana" # SRANDMEMBER 并不会修改集合内容 redis> SMEMBERS fruit 1) "apple" 2) "cherry" 3) "banana" # 集合为空时返回 nil 或者空数组 redis> SRANDMEMBER not-exists (nil) redis> SRANDMEMBER not-eixsts 10 (empty list or set) 讨论
SPOP key
时间复杂度:O(1)
移除并返回集合中的一个随机元素。如果只想获取一个随机元素,但不想该元素从集合中被移除的话,可以使用SRANDMEMBER key [count] 命令。
redis> SMEMBERS db 1) "MySQL" 2) "MongoDB" 3) "Redis" redis> SPOP db "Redis" redis> SMEMBERS db 1) "MySQL" 2) "MongoDB" redis> SPOP db "MySQL" redis> SMEMBERS db 1) "MongoDB"
spop从集合弹出 srandmembe不会破坏集合
下面我们看看应用: CSDN的点赞状态就可以用set集合进行处理。类似于点赞、踩这种场景,状态不重复,就可以set集合。
还有CSDN发表博文的时候,给文章打标签,标签就可以存储在set集合中
除此之外,set结构可以⽤来存储活动中奖的⽤户ID,因为有去重功能,可以保证同⼀个⽤户不会中奖两次。
下面看看集合间的API
5.sdiff sinter sunion¶
分别是差集,交集,并集。
这个玩法就比较多了。
比如微信上,将每个人拥有的群id都存储在每个人的set集合中,我们只要对两个人的集合取交集,就可以得出我和他的公共群聊的个数。