我试图添加一个值到一个列表,但只有当它还没有被添加。
是否有一个命令来做这件事,或者是否有一种方法来测试列表中值的存在?
谢谢!
我也需要这样做。我想从列表中删除这个元素,然后再添加它。如果元素不在列表中,redis将返回0,因此没有错误
lrem mylist 0 myitem
rpush mylist myitem
正如Tommaso Barbugli所提到的,如果只需要惟一的值,应该使用集合而不是列表。参见REDIS文档SADD
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SADD myset "World"
(integer) 0
redis> SMEMBERS myset
1) "World"
2) "Hello"
如果要检查集合中是否存在某个值,可以使用SISMEMBER
redis> SADD myset "one"
(integer) 1
redis> SISMEMBER myset "one"
(integer) 1
redis> SISMEMBER myset "two"
(integer) 0
看起来你需要一个集合或者一个有序的集合。
集合具有O(1)成员检验和强制唯一性。
如果你不能使用set(如果你想实现一些阻塞POP/PUSH列表功能),你可以使用一个简单的脚本:
script load 'local exists = false; for idx=1, redis.call("LLEN",KEYS[1]) do if (redis.call("LINDEX", KEYS[1], idx) == ARGV[1]) then exists = true; break; end end; if (not exists) then redis.call("RPUSH", KEYS[1], ARGV[1]) end; return not exists or 0'
这将返回您添加的脚本的SHA代码。
直接调用:
evalsha 3e31bb17571f819bea95ca5eb5747a373c575ad9 1 test-list myval
,
-
3e31bb17571f819bea95ca5eb5747a373c575ad9
(您添加的脚本的SHA代码) -
1
-参数数(1为该函数的常数) -
test-list
-您的列表名称 -
myval
—您需要添加的值
如果新条目是添加的,则返回1;如果该条目已经在列表中,则返回0。
此功能在redis中使用hexists
hexists命令设置。
检查列表中是否存在成员需要O(n),这对于大列表来说是相当昂贵的,并且绝对不是理想的。也就是说,其他人似乎都在给你其他选择。我只会告诉你如何做你要求做的事情,并假设你有很好的理由这样做。我将在Python中做,假设你有一个连接到Redis称为r
,一些列表称为some_list
和一些新项目添加称为new_item
:
lst = r.lrange(list_name, -float('Inf'), float('Inf'))
if new_item not in lst:
r.rpush(list_name, new_item)
我在添加任务工作者队列时遇到了这个问题,因为我想避免添加许多重复的任务。使用Redis集合(正如许多人建议的那样)会很好,但是Redis集合没有像BRPOPLPUSH那样的"阻塞弹出",所以它们不适合任务队列。
那么,这是我的稍微不理想的解决方案(在Python中):
def pushOnlyNewItemsToList(redis, list_name, items):
""" Adds only the items that aren't already in the list.
Though if run simultaneously in multiple threads, there's still a tiny chance of adding duplicate items.
O(n) on the size of the list."""
existing_items = set(redis.lrange(list_name,0,-1))
new_items = set(items).difference(existing_items)
if new_items:
redis.lpush(list_name, *new_items)
注意文档字符串中的注意事项。
如果你真的需要保证没有重复,另一种选择是在Redis管道中运行LREM, LPUSH,如0xAffe的答案。这种方法导致较少的网络流量,但有重新排序列表的缺点。如果你不关心列表顺序,这可能是最好的通用答案。
正如@Eli所说,检查列表中是否存在是一个O(N)的操作,这是非常昂贵的,特别是当列表很大的时候。我也面临着类似的问题。对我来说,使用SET不是一种选择,因为我需要在从列表中删除项时保证插入顺序。Redis SETS以随机顺序删除/检索项目,这对我来说是一个交易破坏者。我想做的是在Redis中维护一个单独的HASH,只是为了检查项目是否存在,然后再将其添加到列表中。这意味着每当我在列表中添加一个项目时,我都必须将其添加到这个辅助数据结构(HASH)中,以支持O(1)查找来检查是否存在。我知道这是在复制数据,但是考虑到其他选项,额外的空间消耗似乎没有那么糟糕。