2013-08-02 9 views
6

Dato è la seguente matrice (ogni blocco [] rappresenta una voce):raccolta Split in oggetti basato su condizioni e occorrenza

[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] 

devo dividerlo in oggetti di tipo 'N' (NObject) dove ogni altro personaggio rappresenta una proprietà specifica di quell'oggetto NObject fino alla successiva occorrenza di "N". Fino alla prima occorrenza di "N", i personaggi appartengono a un altro oggetto (chiamiamolo PObject). Quindi, i compiti devono soddisfare il follwing:

  1. mappa ogni personaggio a una proprietà pObject
  2. Quando i primi occurrs 'N', creare un nuovo NObject
  3. Mappa ogni personaggio a una proprietà di quel NObject
  4. Se si verifica un altro carattere N, creare un nuovo oggetto NO

Attualmente, in pseudocodice la mia soluzione sembra la seguente che trovo è tutt'altro che ideale.

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

che mi dà esattamente quello che voglio:

[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 

Ma con oltre 30 possibili identificatori di proprietà (il che significa 30 condizioni di commutazione) e una proprietà assegnato solo in base al fatto che nOggetto può essere nullo (e creandone uno nuovo ogni occorrenza di "N"): il codice è incredibilmente maleodorante. Ma non so come farlo in modo diverso, magari con funzioni di raccolta integrate, LINQ o qualsiasi altra cosa.

+0

Reflection rimuoverà l'istruzione switch, ma non sono sicuro di aver letto la tua domanda abbastanza bene da comprendere il tuo requisito mi dispiace. – Sayse

+0

Puoi utilizzare la libreria [FastMember] (https://code.google.com/p/fast-member/) del gravell per accedere agli elementi dell'oggetto con il loro nome ('A', 'B', ...) – xanatos

+0

è intenzionale che si aggiungono alle proprietà invece di impostarle? (nobject ?? (CommonBase) pobject) .H + = entry.Value; invece di (nobject ?? (CommonBase) pobject) .H = entry.Value; – ne2dmar

risposta

1

È possibile utilizzare Dizionario per memorizzare coppie chiave-valore anziché creare esplicitamente proprietà per ogni caso possibile. Qualcosa di simile:

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

} 
+0

Purtroppo, ho bisogno delle proprietà perché le accedo direttamente in seguito. :( – user2644817

+0

quindi puoi fare getter di proprietà per accedere al dizionario – ne2dmar

+0

Oh, ho capito Beh, in tal caso il mio esempio è stato scelto un po 'sfortunato. Ho messo gli interi lì per una comprensione più semplice, nella mia soluzione, quelli sono interi, corde e altri oggetti che in alcuni casi, ho bisogno di analizzare ulteriormente :) – user2644817

1

Ho riscritto il codice utilizzando la riflessione e 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; 
      }); 

All'interno del metodo Process è dove è possibile gestire l'elaborazione delle proprietà, in base al loro tipo:

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; 
    } 
} 
Problemi correlati