根据条件和出现将集合拆分为对象

时间:2013-08-02 07:07:23

标签: c# .net arrays linq object

给出以下数组(每个block []代表一个条目):

[A=1] [A=5] [S=3] [A=7] [C=3] [T=2] [F=9] [Z=4] [N] [C=3] [E=8]
[A=7] [N] [Z=6] [Q=1] [P=2] [Y=7] [S=3] [N] 

我需要将其拆分为“N”类型的对象(NObject),其中每个其他字符代表该NObject对象的特定属性,直到下一次出现“N”。直到第一次出现'N',字符属于另一个对象(让我们称之为PObject)。所以任务应该完成以下任务:

  1. 将每个字符映射到PObject属性
  2. 当第一个'N'出现时,创建一个新的NObject
  3. 将每个字符映射到该NObject的属性
  4. 如果出现另一个N字符,请创建一个新的NObject
  5. 目前,在伪代码中我的解决方案看起来如下,我发现它远非理想。

    PObject pobject = new PObject();
    NObject nobject;
    
    CollectionOfKeyValuePairs collection = MyArray.Split('=').MapKeysValues()
    
    foreach(entry in collection) {
        switch(entry.Key):
            case A:
                (nobject ?? (CommonBase) pobject).A += entry.Value; break;
            case B:
                (nobject ?? (CommonBase) pobject).B += entry.Value; break;
            case C:
                (nobject ?? (CommonBase) pobject).C += entry.Value; break;
            case E:
                pobject.E += entry.Value; break;
            case F:
                (nobject ?? (CommonBase) pobject).F += entry.Value; break;
            case G:
                (nobject ?? (CommonBase) pobject).G += entry.Value; break;
            case H:
                (nobject ?? (CommonBase) pobject).H += entry.Value; break;
            ...
            ...
            ...
            case N:
                 nobject = new NObject();
            ....
            ....
        }
    }
    

    这给了我我想要的东西:

    [pobject]
    A = 23
    B = 63
    C = 23
    ...
    
    [nobject]
    A = 34
    B = 82
    C = 12
    ...
    
    [nobject]
    H = 236
    K = 2
    ...
    
    [nobject]
    // N occurred in array, but no properties followed
    

    但是有超过30个可能的属性标识符(这意味着30个切换条件)和仅基于nobject可能为空的事实分配的属性(并且每个'N'字符出现创建一个新的属性):代码令人难以置信的臭。但我不知道如何做到与众不同,可能还有内置集合函数,LINQ或其他任何东西。

2 个答案:

答案 0 :(得分:1)

您可以使用Dictionary来存储键值对,而不是为每种可能的情况显式创建属性。类似的东西:

List<Dictionary<char,int>> listOfPNObjects = new List<Dictionary<char,int>>();
listOfPNObjects.Add(new Dictionary<char,int>())    //create default P dictionary
foreach(entry in collection) {
    if(entry.Key == N)
    {
            listOfPNObjects.Add(new Dictionary<char,int>());
    }
    else
    {
          listOfPNObjects[listOfPNObjects.Count - 1].Add(entry.key, entry.value);
    }

}

答案 1 :(得分:1)

我使用了反射和LINQ重写了你的代码:

var objects = keyValuePairList
    .Aggregate<KeyValuePair<string, dynamic>, List<CommonBase>>(
        new List<CommonBase>(), (a, p) =>
            {
                CommonBase cObject;
                if (p.Key == "N")
                {
                    cObject = new NObject();
                    a.Add(cObject);
                }
                if (a.Count == 0)
                {
                    cObject = new PObject();
                    Process(p, ref cObject);
                    a.Add(cObject);
                }
                else
                {
                    cObject = a.Last();
                    Process(p, ref cObject);
                }
                return a;
            });

Process方法内部,您可以根据其类型处理属性:

private static void Process(
        KeyValuePair<string, dynamic> kvPair,
        ref CommonBase cObject)
{
    var propertyInfo = typeof(CommonBase).GetProperty(kvPair.Key);
    switch (propertyInfo.PropertyType.FullName)
    {
        case "System.Int32":
            propertyInfo
                .SetValue(cObject,
                    (int)propertyInfo.GetValue(cObject) + (int)kvPair.Value);
            break;
    }
}