Redis Lists (Part 2)

This lesson covers advanced list operations including querying, modifying, and inserting elements.

LINDEX: Get Element by Index

LINDEX retrieves an element by its index without removing it.

Basic Usage

REDIS
LPUSH mylist "one" "two" "three" "four" "five"

# Get the first element (index 0)
LINDEX mylist 0
"five"

# Get the second element
LINDEX mylist 1
"four"

# Get the last element
LINDEX mylist -1
"one"

# Get the second to last element
LINDEX mylist -2
"two"

Index Out of Range

REDIS
# Returns nil when index is out of range
LINDEX mylist 10
(nil)

LINDEX mylist -10
(nil)
💡 Performance: LINDEX has O(N) time complexity, where N is the absolute index value. Head and tail access is fast; middle access is slow.

LSET: Set Element by Index

LSET modifies the element at a specified index.

Basic Usage

REDIS
LRANGE mylist 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"

# Modify the first element
LSET mylist 0 "FIRST"
OK

# Modify the last element
LSET mylist -1 "LAST"
OK

LRANGE mylist 0 -1
1) "FIRST"
2) "four"
3) "three"
4) "two"
5) "LAST"

Index Out of Range

REDIS
LSET mylist 10 "value"
(error) ERR index out of range
⚠️ Note: LSET can only modify existing indexes — it cannot insert new elements.

LINSERT: Insert Before or After a Pivot

LINSERT inserts a new element before or after a specified pivot element.

LINSERT BEFORE: Insert Before

REDIS
LRANGE mylist 0 -1
1) "FIRST"
2) "four"
3) "three"
4) "two"
5) "LAST"

# Insert "BEFORE_THREE" before "three"
LINSERT mylist BEFORE "three" "BEFORE_THREE"
(integer) 6  # Returns list length

LRANGE mylist 0 -1
1) "FIRST"
2) "four"
3) "BEFORE_THREE"
4) "three"
5) "two"
6) "LAST"

LINSERT AFTER: Insert After

REDIS
# Insert "AFTER_THREE" after "three"
LINSERT mylist AFTER "three" "AFTER_THREE"
(integer) 7

LRANGE mylist 0 -1
1) "FIRST"
2) "four"
3) "BEFORE_THREE"
4) "three"
5) "AFTER_THREE"
6) "two"
7) "LAST"

Pivot Not Found

REDIS
# Specified pivot element does not exist
LINSERT mylist BEFORE "notexist" "value"
(integer) -1  # Returns -1 when pivot not found
⚠️ Performance warning: LINSERT has O(N) time complexity — it needs to traverse the list to find the pivot. This is slow on very long lists.

LREM: Remove Elements by Value

LREM removes elements from the list that match a specified value.

Basic Usage

REDIS
LPUSH mylist "a" "b" "a" "c" "a" "d"

LRANGE mylist 0 -1
1) "d"
2) "a"
3) "c"
4) "a"
5) "b"
6) "a"

# Remove 2 occurrences of "a" from the head
LREM mylist 2 "a"
(integer) 2  # Deleted 2

LRANGE mylist 0 -1
1) "d"
2) "c"
3) "b"
4) "a"

Parameter Reference

Parameter Description
count > 0 Remove count occurrences from the head
count < 0 Remove abs(count) occurrences from the tail
count = 0 Remove all matching elements

Remove from Tail

REDIS
LPUSH mylist "a" "b" "a" "c" "a"

# Remove 1 occurrence of "a" from the tail
LREM mylist -1 "a"
(integer) 1

Remove All Matching Elements

REDIS
LPUSH mylist "a" "b" "a" "c" "a"

# Remove all "a"
LREM mylist 0 "a"
(integer) 3

LRANGE mylist 0 -1
1) "c"
2) "b"

RPOPLPUSH: Move Elements

RPOPLPUSH pops the tail element from one list and pushes it to the head of another list.

Basic Usage

REDIS
# Source list
LPUSH source "one" "two" "three"

# Destination list
LPUSH destination "a" "b"

# Move tail of source to head of destination
RPOPLPUSH source destination
"one"  # Returns the moved element

LRANGE source 0 -1
1) "three"
2) "two"

LRANGE destination 0 -1
1) "one"
2) "a"
3) "b"

Use Case: Circular Queue

REDIS
# Move a task from tail back to head for round-robin processing
RPOPLPUSH queue:task queue:task

Use Case: Backup Queue

REDIS
# Move task to backup queue while processing
RPOPLPUSH queue:task queue:backup

# If processing fails, the task can be recovered from the backup queue

BRPOPLPUSH: Blocking Move

BRPOPLPUSH is the blocking version of RPOPLPUSH.

REDIS
# If source list is empty, block wait for up to 10 seconds
BRPOPLPUSH source destination 10
💡 Use case: BRPOPLPUSH is commonly used for reliable message queues to ensure no messages are lost.

LMOVE: Move Elements (Redis 6.2+)

LMOVE is a generalized version of RPOPLPUSH that lets you specify both the source and destination positions.

REDIS
# Pop from the right of source, push to the left of destination
LMOVE source destination RIGHT LEFT

# Pop from the left of source, push to the right of destination
LMOVE source destination LEFT RIGHT

Advanced List Applications

Use Case 1: Pagination

REDIS
# Article list
LPUSH articles "article:1" "article:2" ... "article:100"

# Page 1 (10 items per page)
LRANGE articles 0 9

# Page 2
LRANGE articles 10 19

# Page 3
LRANGE articles 20 29

Use Case 2: Recent Contacts

REDIS
# Add a contact to the recent list
LPUSH contacts:user:1 "user:2"

# If already exists, remove first then add (move to front)
LREM contacts:user:1 0 "user:2"
LPUSH contacts:user:1 "user:2"

# Get recent 10 contacts
LRANGE contacts:user:1 0 9

Use Case 3: Round-Robin Scheduling

REDIS
# Task list
LPUSH tasks "task1" "task2" "task3"

# Round-robin: pop task, process it, then put it back at the tail
RPOPLPUSH tasks tasks
"task1"  # Process task1

# Next poll will get task2

Use Case 4: Capped Log

REDIS
# Add a log entry
LPUSH log:app "log message"

# Keep the most recent 1000 log entries
LTRIM log:app 0 999

# View recent logs
LRANGE log:app 0 99

List Performance Optimization

1. Avoid Middle Operations

REDIS
# ❌ Poor performance: insert or delete in the middle
LINSERT mylist BEFORE "middle" "new"
LREM mylist 1 "middle"

# ✅ Good performance: only operate at head and tail
LPUSH mylist "new"
LPOP mylist

2. Avoid Large Lists

REDIS
# ❌ List too large
LLEN mylist
(integer) 1000000

# ✅ Use LTRIM to limit length
LTRIM mylist 0 9999

3. Fetch in Batches with LRANGE

REDIS
# ❌ Fetch a huge range at once
LRANGE mylist 0 -1

# ✅ Fetch in batches
LRANGE mylist 0 99
LRANGE mylist 100 199

4. Choose the Right Data Structure

Requirement Recommended Data Structure
Queue/Stack List
Latest N items List + LTRIM
Pagination List + LRANGE
Deduplicated list Set or Sorted Set
Weighted sorting Sorted Set

List Limitations

1. Slow Element Lookup

REDIS
# Finding a specific value requires traversing the entire list
LINDEX mylist 500000  # O(N) operation, very slow

2. Slow Middle Operations

REDIS
# Inserting or deleting in the middle requires shifting elements
LINSERT mylist BEFORE "middle" "new"  # O(N)

3. Cannot Find Index by Value

Redis does not provide a command to find the index of a value by its content. This must be implemented at the application level.

❓ FAQ

Q What's the difference between LINDEX and LRANGE?
A LINDEX returns a single element; LRANGE returns a list of elements. LINDEX mylist 0 is equivalent to LRANGE mylist 0 0.
Q How do I insert an element in the middle of a list?
A Use LINSERT, but performance is poor. If you need frequent middle insertions, consider using a different data structure.
Q Is RPOPLPUSH atomic?
A Yes. RPOPLPUSH is atomic — either it succeeds completely or fails completely.
Q How do I implement a priority queue?
A Use multiple lists (e.g., queue:high, queue:low). Check high-priority queues first, then low-priority ones.
Q What's the difference between list and set?
A Lists are ordered and allow duplicates; sets are unordered with unique elements. Use lists for order, sets for deduplication.

📖 Summary

📝 Exercises

  1. Index operations: Create a list, use LINDEX to get elements at different positions, use LSET to modify elements
  2. Insert and delete: Use LINSERT to insert in the middle, use LREM to remove elements by value
  3. Element movement: Use RPOPLPUSH to implement a circular queue for task round-robin
  4. Pagination: Create a list with 20 elements and implement pagination with 5 items per page

Next Lesson

In the next lesson, we will learn Redis Sets (Part 1), covering basic set operations.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏