Codibre.DictionaryChain
1.1.10
dotnet add package Codibre.DictionaryChain --version 1.1.10
NuGet\Install-Package Codibre.DictionaryChain -Version 1.1.10
<PackageReference Include="Codibre.DictionaryChain" Version="1.1.10" />
paket add Codibre.DictionaryChain --version 1.1.10
#r "nuget: Codibre.DictionaryChain, 1.1.10"
// Install Codibre.DictionaryChain as a Cake Addin #addin nuget:?package=Codibre.DictionaryChain&version=1.1.10 // Install Codibre.DictionaryChain as a Cake Tool #tool nuget:?package=Codibre.DictionaryChain&version=1.1.10
DictionaryChain extension for any .net project
Why
Some highly accessed lists can benefit from a chained dictionary structure. Let's say you have three fields where you apply a equality comparison to choose between the items of the list. This operation, unless you do a binary search, will have a processing complexity of O(N). However, if you create an instance of chained dictionaries with depth 3, where the keys for each level are the values for each field, you can have the same result in O(1), as long as you have stablished uniqueness for the fields used to build this instance. If not, you can have a list with every list item that matches that path, and now you'll have to traverse much fewer items than before, as the items are distributed between the nodes!
Long story short, you can better the performance of you application by caching those chained dictionaries on strategic points, making much less list traversals throughout your application execution!
How to use it
First, import the application namespace:
using Codibre.DictionaryChain
Now, you'll have the method ToDictionaryChain in every IEnumerable<> instance, and you just have to build it. Let's say you have a list with items that look like this:
struct Person {
public string Name;
public string City;
public string State;
public string Country;
}
If so, you may build a chain of dictionaries using the field country, state and city
var chain = list.ToDictionaryChain(x => x.Country, x => x.State, x => x.City);
The object chain will have a type like this:
IDictionary<string, IDictionary<string, IDictionary<string, List<Person>>>
So, if you want to find every listed person that lives in the country US, state of Florida, in the city of Tallahassee, you just have to do:
var persons = chain['US']['Florida']['Tallahassee'];
Or
if (!chain.TryGetValue('US', out var stateChain)
|| !stateChain.TryGetValue('Florida', out var cityChain)
|| !cityChain.TryGetValue('Tallahassee', out var persons)
) return null;
return persons;
Custom Leaf Values
Let's say you don't care about each individual value, but just one of them, or even some transformation based on the list of values that goes on each leaf. In that case, you can use the ToDictionaryChain variant where you specify the leaf construction:
var chain = list.ToDictionaryChain(
() => 0, // Initializes the leaf value
(acc, newItem) => acc + (newItem.Name.StartsWith("A") ? 1 : 0), // Transforms the leaf value based on the value of a new item
x => x.Country, x => x.State, x.City)
That way, each leaf will have the number of people in each city with a name starting with "A"!
Limitation
This package, for now, can only infer a strong chain of Dictionary types up to depth 7, which we hope will be enough for most cases. If you need more than that, though, the result object will be an instance of ChainedDictionary. If you use it directly, you'll need to do some type checking at each level to check (or cast) wether it is another level, or already the leaf, as this object doesn't have the type of every level strongly defined. The best way to deal with this situation is to use the method MakeDictionary, just after creating it, like this:
var chain list.ToDictionary(
x => x.Country,
x => x.State,
x => x.City,
x => x.BirthCountry,
x => x.BirthState,
x => x.BirthCity,
x => x.Age,
x => x.Sex,
).MakeDictionary<Dictionary<string, Dictionary<string,
Dictionary<string,
Dictionary<string,
Dictionary<string,
Dictionary<string,
Dictionary<int,
Dictionary<SexEnum, Person>
>
>
>
>
>
>>>()
MakeDictionary will do some reflection operations to convert the ChainedDictionary into an instance of the chain of Dictionaries provided as type argument. It does have an overload so, the idea is not to use it every time, but to load it in memory once, then letting it being memoized for some time, to avoid repeating the operation and optimizing the query. Does it look good? No, it does not, but it is the better we could do with the current C# design, and it'll still speed up your application!
License
Licensed under MIT.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.1.10 | 210 | 12/11/2023 |
1.1.9 | 122 | 12/11/2023 |
1.1.8 | 138 | 12/11/2023 |
1.1.7 | 127 | 12/11/2023 |
1.1.6 | 130 | 12/11/2023 |
1.1.5 | 121 | 12/11/2023 |
1.1.4 | 119 | 12/11/2023 |
1.1.3 | 140 | 12/11/2023 |
1.1.2 | 136 | 12/10/2023 |
1.1.1 | 114 | 12/10/2023 |
1.1.0 | 132 | 12/10/2023 |
1.0.4 | 135 | 12/9/2023 |
1.0.3 | 136 | 12/7/2023 |