【问题标题】:Split collection into objects based on condition and occurrence根据条件和发生将集合拆分为对象
【发布时间】:2013-08-03 08:42:40
【问题描述】:

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

[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

目前,在伪代码中,我的解决方案如下所示,我发现这远非理想。

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 可能为 null 的属性分配的属性(并且每个 'N' char 出现创建一个新的):代码非常难闻.但我不知道如何做到这一点,也许使用内置集合函数、LINQ 或其他任何东西。

【问题讨论】:

  • Reflection 会删除您的 switch 语句,但我不确定我是否已充分阅读您的问题以理解您的要求,抱歉。
  • 您可以使用gravell 的FastMember 库通过名称('A'、'B'、...)访问对象的元素
  • 您是否有意添加属性而不是设置属性? (nobject ?? (CommonBase) pobject).H += entry.Value;而不是 (nobject ?? (CommonBase) pobject).H = entry.Value;

标签: c# .net arrays linq object


【解决方案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;
    }
}

【讨论】:

    【解决方案2】:

    您可以使用 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);
        }
    
    }
    

    【讨论】:

    • 不幸的是,我需要这些属性,因为我稍后会直接访问它们。 :(
    • 然后你可以让属性获取器访问字典
    • 哦,我明白了。好吧,在那种情况下,我选择的例子有点不走运。我把整数放在那里以便于理解,在我的解决方案中,这些是整数、字符串和其他对象,在某些情况下,我需要进一步解析。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-23
    • 1970-01-01
    • 1970-01-01
    • 2022-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多