Le problème est que la conception de la structure des données ne correspond pas aux besoins : Il est nécessaire de stocker plusieurs en-têtes pour le même XPos. C'est pourquoi, SortedList<XPos, value>
ne doit pas avoir une valeur de Header
mais une valeur de List<Header>
. Il s'agit d'une modification simple et mineure, mais elle résout tous les problèmes et évite d'en créer de nouveaux comme le font d'autres solutions proposées (voir l'explication ci-dessous) :
using System;
using System.Collections.Generic;
namespace TrySortedList {
class Program {
class Header {
public int XPos;
public string Name;
}
static void Main(string[] args) {
SortedList<int, List<Header>> sortedHeaders = new SortedList<int,List<Header>>();
add(sortedHeaders, 1, "Header_1");
add(sortedHeaders, 1, "Header_2");
add(sortedHeaders, 2, "Header_3");
foreach (var headersKvp in sortedHeaders) {
foreach (Header header in headersKvp.Value) {
Console.WriteLine(header.XPos + ": " + header.Name);
}
}
}
private static void add(SortedList<int, List<Header>> sortedHeaders, int xPos, string name) {
List<Header> headers;
if (!sortedHeaders.TryGetValue(xPos, out headers)){
headers = new List<Header>();
sortedHeaders[xPos] = headers;
}
headers.Add(new Header { XPos = xPos, Name = name });
}
}
}
Output:
1: Header_1
1: Header_2
2: Header_3
Veuillez noter que l'ajout d'une clé "amusante", comme l'ajout d'un nombre aléatoire ou le fait de prétendre que deux XPos ayant la même valeur sont différents, entraîne de nombreux autres problèmes. Par exemple, il devient difficile, voire impossible, de supprimer un en-tête particulier.
Notez également que les performances de tri sont bien meilleures si seulement quelques List<Header>
doivent être triés que chaque Header
. Exemple : S'il y a 100 XPos et que chacun a 100 en-têtes, 10000 Header
doivent être triés par rapport à 100 List<Header>
.
Bien entendu, cette solution présente également un inconvénient : s'il y a de nombreux XPos avec un seul en-tête, autant de listes doivent être créées, ce qui représente un certain surcoût.
Mise à jour 22.12.2021
J'ai enfin trouvé le temps d'écrire une véritable collection intitulée SortedBucketCollection
qui se comporte comme un SortedList
. Il utilise 2 clés pour chaque élément, la première étant la même que celle d'un SortedList
et de nombreux éléments peuvent avoir la même valeur pour cette clé. La seconde clé est utilisée pour différencier les éléments partageant les mêmes valeurs pour la clé 1. SortedBucketCollection
utilise moins d'espace de stockage que SortedList<int, List<Header>>
parce qu'il utilise pour chaque "seau" une liste chaînée et non une liste d'adresses. List<>
.
Code utilisant SortedBucketCollection
ressemble à ceci :
en utilisant System ;
namespace SortedBucketCollectionDemo {
public record FinanceTransaction
(int No, DateTime Date, string Description, decimal Amount);
class Program {
static void Main(string[] args) {
//Constructing a SortedBucketCollection
var transactions =
new SortedBucketCollection<DateTime, int, FinanceTransaction>
(ft=>ft.Date, ft=>ft.No);
var date1 = DateTime.Now.Date;
//Adding an item to SortedBucketCollection
transactions.Add(new FinanceTransaction(3, date1, "1.1", 1m));
transactions.Add(new FinanceTransaction(1, date1, "1.2", 2m));
transactions.Add(new FinanceTransaction(0, date1, "1.3", 3m));
var date2 = date1.AddDays(-1);
transactions.Add(new FinanceTransaction(1, date2, "2.1", 4m));
transactions.Add(new FinanceTransaction(2, date2, "2.2", 5m));
//Looping over all items in a SortedBucketCollection
Console.WriteLine("foreach over all transactions");
foreach (var transaction in transactions) {
Console.WriteLine(transaction.ToString());
}
//Accessing one particular transaction
var transaction12 = transactions[date1, 1];
//Removing a transaction
transactions.Remove(transaction12!);
//Accessing all items of one day
Console.WriteLine();
Console.WriteLine("foreach over transactions of one day");
Console.WriteLine(date1);
foreach (var transaction in transactions[date1]) {
Console.WriteLine(transaction.ToString());
}
}
}
}
Sortie du premier foreach :
FinanceTransaction { No = 1, Date = 07.11.2021 00:00:00, Description = 2.1, Amount = 4 }
FinanceTransaction { No = 2, Date = 07.11.2021 00:00:00, Description = 2.2, Amount = 5 }
FinanceTransaction { No = 0, Date = 08.11.2021 00:00:00, Description = 1.3, Amount = 3 }
FinanceTransaction { No = 1, Date = 08.11.2021 00:00:00, Description = 1.2, Amount = 2 }
FinanceTransaction { No = 3, Date = 08.11.2021 00:00:00, Description = 1.1, Amount = 1 }
Notez que les éléments ne sont pas itérés dans l'ordre dans lequel ils ont été ajoutés, mais triés par leur key1
y key2
.
Pour une description détaillée de SortedBucketCollection
et le code source, voir mon article sur CodeProject SortedBucketCollection : Une liste triée efficace en termes de mémoire, acceptant plusieurs éléments avec la même clé.