I need a multi-dimensional data structure, where each dimension is a small list which is known at design time.
At different places in my program, I'd like to be able to access the data "sliced" by different dimensions, in strongly-typed fashion.
I've put some sample code below that works for a 2D example using nested interfaces, but I imagine it would get pretty horrendous in 3D or 4D. As @kvb identified, the boilerplate code required would grow exponentially.
Does anyone have a better suggestion? By which I mean, keeping the code required simple/short/easy to understand, while still retaining the ability to do things along the following lines:
Data a = new Data(...)
...
SomeMethodThatOnlyCaresAboutRedThings(a.Red) // takes a IBySize<T>
...
SomeMethodThatOnlyCaresAboutBigThings(a.Big) // takes a IByColour<T>
...
This avoids those methods having to know about parts of the data structure that aren't relevant to them, hence making them more easily testable.
I've used colours/sizes here purely as an example, apologies for inadvertently misleading anyone that these choices were meaningful. T could be a simple data item like a float or some other simple data structure.
Tagged as F# and C# as I'd be happy with a solution in either.
public interface IByColour<T>
{
T Green { get; }
T Red { get; }
T Blue { get; }
}
public interface IBySize<T>
{
T Small { get; }
T Big { get; }
}
internal class ByColour<T> : IByColour<T>
{
public T Green { get; private set; }
public T Red { get; private set; }
public T Blue { get; private set; }
internal ByColour(T green, T red, T blue)
{
Green = green;
Red = red;
Blue = blue;
}
}
internal class BySize<T> : IBySize<T>
{
public T Small { get; private set; }
public T Big { get; private set; }
internal BySize(T small, T big)
{
Small = small;
Big = big;
}
}
public class Data<T> : IByColour<IBySize<T>>, IBySize<IByColour<T>>
{
public IBySize<T> Green { get; private set; }
public IBySize<T> Red { get; private set; }
public IBySize<T> Blue { get; private set; }
public IByColour<T> Small { get; private set; }
public IByColour<T> Big { get; private set; }
public Data(IBySize<T> green, IBySize<T> red, IBySize<T> blue)
{
Green = green;
Red = red;
Blue = blue;
Small = new ByColour<T>(Green.Small, Red.Small, Blue.Small);
Big = new ByColour<T>(Green.Big, Red.Big, Blue.Big);
}
}
EDIT: to clarify what I mean by "better", a desirable property my solution has, and explain how I'd like to use it.
Some of the advantages in Multidimensional database are: Increased Performance: The performance is much better than that of normal databases such as the relational database. Better Data Presentation: The data in a multi-faceted and contains many different factors. The data presentation is great distance superior to conventional databases.
The multi-Dimensional Data Model is a method which is used for ordering data in the database along with good arrangement and assembling of the contents in the database.
However, dealing with multi-dimensional datasets with typically more than two attributes start causing problems, since our medium of data analysis and communication is typically restricted to two dimensions.
The data is stored as a record in a row and each record divided into columns. Below are the examples of the multidimensional array: MDB – Multidimensional Database: It is a type of database that has the data warehouse and OLAP (online analytical processing).
This sounds like a good use of a good old fashioned DataTable
. Then you can use Linq to slice and dice however you want, and any unique types created by different combinations of columns selected are generated automatically by the compiler. All the columns in a DataTable
are strongly typed, as are results of queries against them. Also, the DataColumns
in a DataTable
can have any type at all, including complex objects or you own enumeration types.
If you want to stick with a more mathy / immutable / F# way of doing things, you could use an array or List
of Tuple<Type1, Type2, .. TypeN>
, which is basically the same thing as a DataTable
anyway.
If you gave a little more background on what you're modeling I could provide an example. I'm not sure if the code you posted is supposed to represent clothes, images (RGB color space) or something completely different.
[An hour later] Well, no update from the OP so I'll proceed with an example where I use List<Tuple<x, y, ..n>>
and assume the objects are clothing items.
// Some enums
public enum Size { Small, Medium, Large }
public enum Color { Red, Green, Blue, Purple, Brown }
public enum Segment { Men, Women, Boys, Girls, Infants }
// Fetches the actual list of items, where the object
// item is the actual shirt, sock, shoe or whatever object
static List<Tuple<Size, Color, Segment, object>> GetAllItems() {
return new List<Tuple<Size, Color, Segment, object>> {
Tuple.Create(Size.Small, Color.Red, Segment.Boys, (object)new { Name="I'm a sock! Just one sock." }),
Tuple.Create(Size.Large, Color.Blue, Segment.Infants, (object)new { Name="Baby hat, so cute." }),
Tuple.Create(Size.Large, Color.Green, Segment.Women, (object)new { Name="High heels. In GREEN." }),
};
}
static void test() {
var allItems = GetAllItems();
// Lazy (non-materialized) definition of a "slice" of everything that's Small
var smallQuery = allItems.Where(x => x.Item1 == Size.Small);
// Lazy map where the key is the size and the value is
// an IEnumerable of all items that are of that size
var sizeLookup = allItems.ToLookup(x => x.Item1, x => x);
// Materialize the map as a dictionary the key is the size and the
// value is a list of all items that are of that size
var sizeMap = sizeLookup.ToDictionary(x => x.Key, x => x.ToList());
// Proof:
foreach (var size in sizeMap.Keys) {
var list = sizeMap[size];
Console.WriteLine("Size {0}:", size);
foreach (var item in list) {
Console.WriteLine(" Item: {{ Size={0}, Color={1}, Segment={2}, value={3} }}",
item.Item1, item.Item2, item.Item3, item.Item4);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With