开发者

Is this more suited for key value storage or a tree?

开发者 https://www.devze.com 2022-12-23 21:05 出处:网络
I\'m trying to figure out the best way to represent some data. It basically follows the form Manufacturer.Product.Attribute = Value. Something like:

I'm trying to figure out the best way to represent some data. It basically follows the form Manufacturer.Product.Attribute = Value. Something like:

Acme.*.MinimumPrice = 100

Acme.ProductA.MinimumPrice = 50

Acme.ProductB.MinimumPrice = 60

Acme.ProductC.DefaultColor = Blue

So the minimum price across all Acme products is 100 except in the case of product A and B. I want to store this data in C# and have some function where GetValue("Acme.ProductC.MinimumPrice") returns 100 but GetValue("Acme.ProductA.MinimumPrice") return 50.

I'm not sure how to best represent the data. Is there a clean way to code this in C#?

Edit: I may not have been 开发者_如何学Cclear. This is configuration data that needs to be stored in a text file then parsed and stored in memory in some way so that it can be retrieved like the examples I gave.


Write the text file exactly like this:

Acme.*.MinimumPrice = 100
Acme.ProductA.MinimumPrice = 50
Acme.ProductB.MinimumPrice = 60
Acme.ProductC.DefaultColor = Blue

Parse it into a path/value pair sequence:

foreach (var pair in File.ReadAllLines(configFileName)
                         .Select(l => l.Split('='))
                         .Select(a => new { Path = a[0], Value = a[1] }))
{
    // do something with each pair.Path and pair.Value
}

Now, there two possible interpretations of what you want to do. The string Acme.*.MinimumPrice could mean that for any lookup where there is no specific override, such as Acme.Toadstool.MinimumPrice, we return 100 - even though there is nothing referring to Toadstool anywhere in the file. Or it could mean that it should only return 100 if there are other specific mentions of Toadstool in the file.

If it's the former, you could store the whole lot in a flat dictionary, and at look up time keep trying different variants of the key until you find something that matches.

If it's the latter, you need to build a data structure of all the names that actually occur in the path structure, to avoid returning values for ones that don't actually exist. This seems more reliable to me.

So going with the latter option, Acme.*.MinimumPrice is really saying "add this MinimumPrice value to any product that doesn't have its own specifically defined value". This means that you can basically process the pairs at parse time to eliminate all the asterisks, expanding it out into the equivalent of a completed version of the config file:

Acme.ProductA.MinimumPrice = 50
Acme.ProductB.MinimumPrice = 60
Acme.ProductC.DefaultColor = Blue
Acme.ProductC.MinimumPrice = 100

The nice thing about this is that you only need a flat dictionary as the final representation and you can just use TryGetValue or [] to look things up. The result may be a lot bigger, but it all depends how big your config file is.

You could store the information more minimally, but I'd go with something simple that works to start with, and give it a very simple API so that you can re-implement it later if it really turns out to be necessary. You may find (depending on the application) that making the look-up process more complicated is worse over all.


I'm not entirely sure what you're asking but it sounds like you're saying either.

I need a function that will return a fixed value, 100, for every product ID except for two cases: ProductA and ProductB

In that case you don't even need a data structure. A simple comparison function will do

int GetValue(string key) { 
  if ( key == "Acme.ProductA.MinimumPrice" ) { return 50; }
  else if (key == "Acme.ProductB.MinimumPrice") { return 60; }
  else { return 100; }
}

Or you could have been asking

I need a function that will return a value if already defined or 100 if it's not

In that case I would use a Dictionary<string,int>. For example

class DataBucket {
  private Dictionary<string,int> _priceMap = new Dictionary<string,int>();
  public DataBucket() {
    _priceMap["Acme.ProductA.MinimumPrice"] = 50;
    _priceMap["Acme.ProductB.MinimumPrice"] = 60;
  }   
  public int GetValue(string key) { 
    int price = 0;
    if ( !_priceMap.TryGetValue(key, out price)) {
      price = 100;
    }
    return price;
  }
}


One of the ways - you can create nested dictionary: Dictionary<string, Dictionary<string, Dictionary<string, object>>>. In your code you should split "Acme.ProductA.MinimumPrice" by dots and get or set a value to the dictionary corresponding to the splitted chunks.

Another way is using Linq2Xml: you can create XDocument with Acme as root node, products as children of the root and and attributes you can actually store as attributes on products or as children nodes. I prefer the second solution, but it would be slower if you have thousands of products.


I would take an OOP approach to this. The way that you explain it is all your Products are represented by objects, which is good. This seems like a good use of polymorphism.

I would have all products have a ProductBase which has a virtual property that defaults

virtual MinimumPrice { get { return 100; } }

And then your specific products, such as ProductA will override functionality:

override MinimumPrice { get { return 50; } }
0

精彩评论

暂无评论...
验证码 换一张
取 消