LRANGE:获取指定索引范围上的元素

用户除了可以使用 LINDEX 命令获取给定索引上的单个元素之外,还可以使用 LRANGE 命令获取给定索引范围上的多个元素:

LRANGE list start end
bash

LRANGE 命令接受一个列表、一个开始索引和一个结束索引作为参数,然后依次返回列表从开始索引到结束索引范围内的所有元素,其中开始索引和结束索引对应的元素也会被包含在命令返回的元素当中。

作为例子,以下代码展示了如何使用 LRANGE 命令去获取 alphabets 列表在不同索引范围内的元素:

redis> LRANGE alphabets 0 3 -- 获取列表索引0至索引3上的所有元素
1) "a" -- 位于索引0上的元素
2) "b" -- 位于索引1上的元素
3) "c" -- 位于索引2上的元素
4) "d" -- 位于索引3上的元素
redis> LRANGE alphabets 2 6
1) "c"
2) "d"
3) "e"
4) "f"
5) "g"
redis> LRANGE alphabets -5 -1
1) "d"
2) "e"
3) "f"
4) "g"
5) "h"
redis> LRANGE alphabets -7 -4
1) "b"
2) "c"
3) "d"
4) "e"
bash

图 4-18 展示了这些 LRANGE 命令是如何根据给定的索引范围去获取列表元素的。

获取列表包含的所有元素

一个快捷地获取列表包含的所有元素的方法,就是使用 0 作为起始索引、-1 作为结束索引去调用 LRANGE 命令,这种方法非常适合于查看长度较短的列表:

redis> LRANGE alphabets 0 -1
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
7) "g"
8) "h"
bash
image 2025 01 03 16 13 26 511
Figure 1. 图4-18 LRANGE 命令获取索引范围内元素的过程

处理超出范围的索引

与 LINDEX 一样,LRANGE 命令也需要处理超出范围的索引:

  • 如果用户给定的起始索引和结束索引都超出了范围,那么 LRANGE 命令将返回空列表作为结果。

  • 如果用户给定的其中一个索引超出了范围,那么 LRANGE 命令将对超出范围的索引进行修正,然后再执行实际的范围获取操作;其中超出范围的起始索引会被修正为 0,而超出范围的结束索引则会被修正为 -1。

以下代码展示了 LRANGE 命令在遇到两个超出范围的索引时,返回空列表的例子:

redis> LRANGE alphabets 50 100
(empty list or set)
redis> LRANGE alphabets -100 -50
(empty list or set)
bash

以下代码展示了 LRANGE 命令在遇到只有一个超出范围的索引时,对索引进行修正并返回元素的例子:

redis> LRANGE alphabets -100 5
1) "a" -- 位于索引0上的元素
2) "b"
3) "c"
4) "d"
5) "e"
6) "f" -- 位于索引5上的元素
redis> LRANGE alphabets 5 100
1) "f" -- 位于索引5上的元素
2) "g"
3) "h" -- 位于索引-1上的元素
bash

在执行 LRANGE alphabets-1005 调用时,LRANGE 命令会把超出范围的起始索引 -100 修正为 0,然后执行 LRANGE alphabets 05 调用;而在执行 LRANGE alphabets 5100 调用时,LRANGE 命令会把超出范围的结束索引 100 修正为 -1,然后执行 LRANGE alphabets 5-1 调用。

其它信息

  • 复杂度:O(N),其中 N 为给定列表的长度。

  • 版本要求:LRANGE 命令从 Redis 1.0.0 开始可用。

示例:分页

对于互联网上每一个具有一定规模的网站来说,分页程序都是必不可少的:新闻站点、博客、论坛、搜索引擎等,都会使用分页程序将数量众多的信息分割为多个页面,使得用户可以以页为单位浏览网站提供的信息,并以此来控制网站每次取出的信息数量。图 4-19 就展示了一个使用分页程序对用户发表的论坛主题进行分割的例子。

image 2025 01 03 16 17 00 123
Figure 2. 图4-19 论坛中的分页示例

代码清单 4-2 展示了一个使用列表实现分页程序的方法,这个程序可以将给定的元素有序地放入一个列表中,然后使用 LRANGE 命令从列表中取出指定数量的元素,从而实现分页这一概念。

代码清单4-2 使用列表实现的分页程序:/list/paging.py
class Paging:

    def __init__(self, client, key):
        self.client = client
        self.key = key

    def add(self, item):
        """
        将给定元素添加到分页列表中。
        """
        self.client.lpush(self.key, item)

    def get_page(self, page_number, item_per_page):
        """
        从指定页数中取出指定数量的元素。
        """
        # 根据给定的 page_number (页数)和 item_per_page (每页包含的元素数量)
        # 计算出指定分页元素在列表中所处的索引范围
        # 例子:如果 page_number = 1 , item_per_page = 10
        # 那么程序计算得出的起始索引就是 0 ,而结束索引则是 9
        start_index = (page_number - 1) * item_per_page
        end_index = page_number * item_per_page - 1
        # 根据索引范围从列表中获取分页元素
        return self.client.lrange(self.key, start_index, end_index)

    def size(self):
        """
        返回列表目前包含的分页元素数量。
        """
        return self.client.llen(self.key)
python

作为例子,我们可以通过执行以下代码,载入并创建出一个针对用户帖子的分页对象:

>>> from redis import Redis
>>> from paging import Paging
>>> client = Redis(decode_responses=True)
>>> topics = Paging(client, "user-topics")
bash

并使用数字 1~19 作为用户帖子的 ID,将它们添加到分页列表中:

>>> from redis import Redis
>>> from paging import Paging
>>> client = Redis(decode_responses=True)
>>> topics = Paging(client, "user-topics")
bash

然后我们就可以使用分页程序,对这些帖子进行分页了:

>>> topics.get_page(1, 5) # 以每页5个帖子的方式,取出第1页的帖子
['19', '18', '17', '16', '15']
>>> topics.get_page(2, 5) # 以每页5个帖子的方式,取出第2页的帖子
['14', '13', '12', '11', '10']
>>> topics.get_page(1, 10) # 以每页10个帖子的方式,取出第1页的帖子
['19', '18', '17', '16', '15', '14', '13', '12', '11', '10']
bash

最后,我们可以通过执行以下代码,取得分页列表目前包含的元素数量:

>>> topics.size()
19
bash