微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 有更好的方法来创建一个多维强类型的数据结构吗?

我需要一个多维数据结构,其中每个维度是在设计时已知的小列表.

在我的程序中的不同地方,我想要以强类型的方式访问不同维度的“切片”数据.

我把下面的一些示例代码放在了使用嵌套接口的二维示例中,但是我想象会在3D或4D中变得非常可怕.如@kvb所示,所需的样板代码将呈指数增长.

有没有人有更好的建议?我的意思是,保持代码需要简单/简短/容易理解,同时仍然保留以下行为的能力:

Data a = new Data(...)
...
SomeMethodThatOnlyCaresAboutRedThings(a.Red) // takes a IBySize<T>
...
SomeMethodThatOnlyCaresAboutBigThings(a.Big) // takes a IByColour<T>
...

这避免了这些方法必须知道数据结构与它们无关的部分,从而使它们更易于测试.

我以纯粹的颜色/大小为例,道歉,无意中误导了任何人这些选择是有意义的. T可以是一个简单的数据项,如浮点数或其他一些简单的数据结构.

标记为F#和C#,因为我会对解决方案感到满意.

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);
    }
}

编辑:澄清我的意思是“更好”,我的解决方案所需要的属性,并解释我想如何使用它.

解决方法

这听起来好像使用了一种很好的老式DataTable.然后,您可以使用Linq切片和骰子,而您想要的,并且由选择的列的不同组合创建的任何唯一类型由编译器自动生成. DataTable中的所有列都是强类型的,对它们的查询结果也是如此.此外,DataTable中的DataColumn可以有任何类型,包括复杂对象或您自己的枚举类型.

如果你想坚持一个更多的情绪/不变/ F#的做事方式,你可以使用一个数组或元组列表,类型1,类型2,类型N>,这与DataTable基本上是一样的.

如果你给出了更多的建模背景,我可以提供一个例子.我不知道你发布的代码是否应该代表衣服,图像(RGB颜色空间)或完全不同的东西.

[一小时后]嗯,没有OP的更新,所以我继续一个例子,我使用List< Tuple< x,y,..n>>并假定物品是服装物品.

// 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,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." }),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);
        }
    }
}

原文地址:https://www.jb51.cc/csharp/96531.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐