StackExchange.Redis: Usando estruturas de dados Redis Lists
Paulo Walraven
Posted on February 19, 2023
Introdução
Redis Lists são listas duplamente vinculadas(linked list) que permitem que você empurre e pop da frente(head
) e da cauda(tail
). Isso permite que você crie o que são essencialmente filas
e pilhas
de Redis Strings. A biblioteca StackExchange.Redis
fornece uma interface intuitiva para trabalhar com listas no IDatabase
.
Redis List na prática
As listas são listas duplamente vinculadas (linked list), o que significa que você pode empurrar ou pular de qualquer lado da lista. No entanto, qualquer tipo de acesso indexado torna-se uma operação O(N), onde N é o número de elementos que você precisa percorrer para alcançar o índice.
Adicionando itens na lista
Vamos adicionar algumas linguagens de programação para o lado esquerdo da lista(head).
var programmingLanguages = new string[] { "C#", "F#", "Elixir", "Java", "JavaScript", "Pascal" };
await database.ListLeftPushAsync(programmingLanguagesKey, programmingLanguages.Select(p => (RedisValue)p).ToArray());
Agora vamos tentar imprimir o primeiro elemento desta lista. As listas são indexadas da esquerda para a direita, consequentemente a última linguagem de programação que adicionamos para a esquerda, será o 0º índice "Pascal”
var lastProgramingLanguage = await database.ListGetByIndexAsync(programmingLanguagesKey, 0);
Console.WriteLine($"The last programming language in the list is: {lastProgramingLanguage}");
// output
The last programming language in the list is: Pascal
E se acessássemos o final da lista, com o índice -1, obteríamos o primeiro elemento que colocamos no lado esquerdo da lista, "C#":
var firstProgramingLanguage = await database.ListGetByIndexAsync(programmingLanguagesKey, -1);
Console.WriteLine($"The first programming language in the list is: {firstProgramingLanguage}");
The first programming language in the list is: C#
Em nossa lista de empresas de tecnologias, agora vamos adicionar a direita. Como estamos pressionando para a direita, o item em questão é adicionado ao final da lista, tornando-o o último elemento da lista se iterarmos na lista.
var technologyCompanies = new string[] { "Microsoft", "Oracle", "Apple", "IBM" };
await database.ListRightPushAsync(technologyCompaniesKey, technologyCompanies.Select(p => (RedisValue)p).ToArray());
Agora, se tentarmos acessar o primeiro elemento da lista, obteremos o primeiro elemento que empurramos para a direita, "Microsoft".
var firstTechnologyCompany = await database.ListGetByIndexAsync(technologyCompaniesKey, 0);
Console.WriteLine($"The first technology in the list is: {firstTechnologyCompany}");
// output
The first technology in the list is: Microsoft
Por outro lado, se acessarmos o último elemento, obteremos "IBM"
var lastTechnologyCompany = await database.ListGetByIndexAsync(technologyCompaniesKey, -1);
Console.WriteLine($"The last technology in the list is: {lastTechnologyCompany}");
// output
The last technology in the list is: IBM
Enumerar uma Lista
Para enumerar uma lista, você pode usar o método ListRange
. Se você passar um índice de início, o intervalo começará a partir daí, e se você passar um índice de parada, ele parará ali, se você não passar nem um início nem um fim, ele irá puxar para trás toda a lista.
Console.WriteLine($"Programming language index 0 to -1: {string.Join(", ", await database.ListRangeAsync(programmingLanguagesKey))}");
Console.WriteLine($"Technology companies index 0 to -2: {string.Join(", ", await database.ListRangeAsync(technologyCompaniesKey, 0, -2))}");
// output
Programming language index 0 to -1: Pascal, JavaScript, Java, Elixir, F#, C#
Technology companies index 0 to -2: Microsoft, Oracle, Apple
Mover elementos entre listas
Você também pode transferir elementos entre listas usando o método ListMove
. Isso aceita duas chaves de lista, bem como o lado de origem e o lado de destino. Estes são os lados da lista de onde você irá pular e empurrar, respectivamente.
await database.ListMoveAsync(programmingLanguagesKey, technologyCompaniesKey, ListSide.Right, ListSide.Left);
127.0.0.1:6379> lrange programming-languages 0 -1
1) "Pascal"
2) "JavaScript"
3) "Java"
4) "Elixir"
5) "F#"
127.0.0.1:6379> lrange technology-companies 0 -1
1) "C#"
2) "Microsoft"
3) "Oracle"
4) "Apple"
5) "IBM"
Lista como uma fila
Você pode usar uma lista Redis como uma fila FIFO de fato pressionando e abrindo de diferentes lados. Convencionalmente, você adicionar para a esquerda, removeria para a direita:
await database.ListLeftPushAsync(programmingLanguagesKey, "Rust");
Console.WriteLine($"Dequeued: {await database.ListRightPopAsync(programmingLanguagesKey)}");
// output
Dequeued: F#
127.0.0.1:6379> lrange programming-languages 0 -1
1) "Rust"
2) "Pascal"
3) "JavaScript"
4) "Java"
5) "Elixir"
Lista como uma pilha
Você também pode fazer com que suas listas atuem como pilhas LIFO, pressionando e retirando das mesmas, por convenção, você normalmente usaria o lado esquerdo.
await database.ListLeftPushAsync(technologyCompaniesKey, "JetBrains");
Console.WriteLine($"Popping: {await database.ListLeftPopAsync(technologyCompaniesKey)}");
// output
Popping: JetBrains
Pesquisando na lista
As listas Redis também permitem encontrar o índice de um item específico usando o método ListPosition
.
Console.WriteLine($"Position of Java: {await database.ListPositionAsync(programmingLanguagesKey, "Java")}");
// ouput
Position of Java: 3
Tamanho da Lista
Você usa o método ListLength
para determinar o tamanho de uma determinada lista.
Console.WriteLine($"There are {await database.ListLengthAsync(technologyCompaniesKey)} technology companies in our list");
// output
There are 5 technology companies in our list
Código completo
using StackExchange.Redis;
using System.Diagnostics;
var options = new ConfigurationOptions
{
EndPoints = new EndPointCollection { "localhost:6379" }
};
var conn = ConnectionMultiplexer.Connect(options);
var database = conn.GetDatabase();
var programmingLanguagesKey = "programming-languages";
var technologyCompaniesKey = "technology-companies";
var keysToDelete = new string[] { programmingLanguagesKey, technologyCompaniesKey };
await database.KeyDeleteAsync(keysToDelete.Select(k => (RedisKey)k).ToArray());
var programmingLanguages = new string[] { "C#", "F#", "Elixir", "Java", "JavaScript", "Pascal" };
await database.ListLeftPushAsync(programmingLanguagesKey, programmingLanguages.Select(p => (RedisValue)p).ToArray());
var lastProgramingLanguage = await database.ListGetByIndexAsync(programmingLanguagesKey, 0);
Console.WriteLine($"The last programming language in the list is: {lastProgramingLanguage}");
var firstProgramingLanguage = await database.ListGetByIndexAsync(programmingLanguagesKey, -1);
Console.WriteLine($"The first programming language in the list is: {firstProgramingLanguage}");
var technologyCompanies = new string[] { "Microsoft", "Oracle", "Apple", "IBM" };
await database.ListRightPushAsync(technologyCompaniesKey, technologyCompanies.Select(p => (RedisValue)p).ToArray());
var firstTechnologyCompany = await database.ListGetByIndexAsync(technologyCompaniesKey, 0);
Console.WriteLine($"The first technology in the list is: {firstTechnologyCompany}");
var lastTechnologyCompany = await database.ListGetByIndexAsync(technologyCompaniesKey, -1);
Console.WriteLine($"The last technology in the list is: {lastTechnologyCompany}");
Console.WriteLine($"Programming language index 0 to -1: {string.Join(", ", await database.ListRangeAsync(programmingLanguagesKey))}");
Console.WriteLine($"Technology companies index 0 to -2: {string.Join(", ", await database.ListRangeAsync(technologyCompaniesKey, 0, -2))}");
await database.ListMoveAsync(programmingLanguagesKey, technologyCompaniesKey, ListSide.Right, ListSide.Left);
await database.ListLeftPushAsync(programmingLanguagesKey, "Rust");
Console.WriteLine($"Dequeued: {await database.ListRightPopAsync(programmingLanguagesKey)}");
await database.ListLeftPushAsync(technologyCompaniesKey, "JetBrains");
Console.WriteLine($"Popping: {await database.ListLeftPopAsync(technologyCompaniesKey)}");
Console.WriteLine($"Position of Java: {await database.ListPositionAsync(programmingLanguagesKey, "Java")}");
Console.WriteLine($"There are {await database.ListLengthAsync(technologyCompaniesKey)} technology companies in our list");
Posted on February 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.