2013-04-22 10 views
5

Ho avuto un'interessante domanda di intervista l'altro giorno, con cui ho davvero faticato. Le specifiche (molto ambiziose) mi impongono di scrivere, in C#, parser per due diversi flussi di dati. Ecco un esempio di made-up del primo flusso:Elaborazione di un formato di feed di dati

30=EUR/USD,35=3,50=ON,51=12.5,52=13.5,50=6M,51=15.4,52=16.2,50=1Y,51=17.2,52=18.3 

dove 30 è la coppia di valute, 35 è il numero di tenori, e 50,51,52 sono il tenore, offerta e chiedere, rispettivamente. L'offerta e la richiesta sono facoltative, ma una tupla tenore-bid-chiesta corretta avrà almeno uno dei due prezzi. Il codice del framework che hanno fornito implicava che il risultato dell'analisi di questa riga fosse costituito da 3 singoli oggetti (istanze DataElement). Ho finito con una dichiarazione di switch piuttosto spiacevole e un'implementazione basata su loop che non sono sicuro abbia funzionato.

Quali tecniche ci sono per leggere questo tipo di flusso? Ho cercato di capire qualcosa con la ricorsione, cosa che non potevo avere ragione.

MODIFICA: In base alla risposta di @ evanmcdonnall (accettata), ecco il codice completo di compilazione e di lavoro, nel caso sia utile per chiunque altro.

 List<DataElement> Parse(string row) 
    { 
     string currency=string.Empty; 
     DataElement[] elements = null; 
     int j = 0; 
     bool start = false; 
     string[] tokens = row.Split(','); 
     for (int i = 0; i < tokens.Length; i++) 
     { 
      string[] kv = tokens[i].Split('='); 

      switch (kv[0]) 
      { 
       case "30": 
        currency = kv[1]; 
        break; 
       case "35": 
        elements = new DataElement[int.Parse(kv[1])]; 
        break; 
       case "50": 
        if (start) 
         j++; 
        elements[j] = new DataElement() { currency = currency, tenor = kv[1] }; 
        start = true; 
        break; 
       case "51": 
        elements[j].bid = double.Parse(kv[1]); 
        break; 
       case "52": 
        elements[j].ask = double.Parse(kv[1]); 
        break; 
      } 
     } 
     return elements.ToList(); 
    } 

I concetti principali sono:

  • Avere un contatore separato per il "ciclo interno" di ripetere elementi in ciascuna linea
  • Avere un flag booleano per indicare quando che "ciclo interno" inizia
  • Assegnare la matrice di oggetti per memorizzare i risultati del "ciclo interno" nel punto in cui è nota la lunghezza (ad esempio, tag 50)
  • Per semplicità e chiarezza, avere una funzione che legge solo un singolo linea, quindi chiamarla più volte da una funzione separata.
+0

Non sembra come questo è un flusso di dati delimitato, né larghezza fissa. Penserei che il tuo metodo sembra ragionevole –

+0

l'ordine degli elementi è sempre lo stesso? Intendo prima che avrai la coppia di valute, poi il numero di tenori e, successivamente, il numero esatto di tuple corrispondenti al numero di tenori? – ppetrov

+1

@AndrewWalters: sembra delimitato in modo abbastanza coerente con ',' ... – mellamokb

risposta

2

Non vedo cosa ci sia di così difficile. Tuttavia, non vedo alcuna soluzione che sarebbe meglio della soluzione molto specifica, iterazione con molti condizionali che ho in mente.

Per prima cosa dividi in virgola, quindi esegui il ciclo su quei token, dividendoli ciascuno sul segno di uguale per ottenere la coppia di valori chiave. Hai i controlli per ogni chiave e un bool da tracciare quando inizi/finisci un oggetto. Leggi la valuta e la usi per ogni oggetto. Si legge il tasto 35 e si trova che ci sono 3 oggetti, quindi si assegna un array di tre oggetti, ciascuno con 3 proprietà; tenore, offerta e chiedere. Quando incontri 50 devi impostare il tuo inizio vero. Imposta 50, 51 e 52 se ci sono. Di seguito è riportato un codice di esempio;

string currency; 
    int j = 0; 
    bool start = false; 
    string[] tokens = line.Split(','); 
    for (int i =0; i < tokens.length; i++) 
    { 
     string[] kv = tokens[i].Split('=') 
     if (kv[0] == 30) 
      currency = kv[1] 
     elseif (kv[0] == 35) 
     { 
      DateElement[] elements = new DataElement[kv[1]]; 
     } 
     elseif (kv[0] == 50) 
     { 
      if (start) 
       j++; 
      start = true; // flip your flag after the condition so it works for element 0 
      elements[j].currency = currency; 
      elements[j].tenor = kv[1]; 
     } 
     elseif (kv[0] == 51) 
      elements[j].bid = kv[1]; 
     elseif (kv[0] == 52)  
      elements[j].ask = kv[1]; 
     // if these optional values aren't there we'll just fall back into the case for 50 
     // and everything will work as expected. 
    } 

Il codice può non essere abbastanza, ma la logica è abbastanza banale e, assumendo il formato linee è corretta, funzionerà sempre.

+1

Non ho detto che era complicato, ho detto che ci ho faticato: c'è una differenza molto evidente tra queste due affermazioni :). Vedo che il tuo codice segue la linea che ho preso, tranne che hai esplicitamente una variabile di conteggio separata (j) mentre ho cercato di combinare il mio con la variabile loop (i) e il tuo approccio di allocare l'array di elementi quando il tag 35 arriva è carino Grazie. – endian

+0

@endian mi scuso. All'inizio questo tipo di elaborazione delle stringhe è alquanto difficile, ma dopo esserti abituato, diventa molto di routine. – evanmcdonnal

+0

Hai bisogno di impostare la variabile 'j' su 0 quando ottieni un nuovo 35 =? – endian

0

30 = EUR/USD, 35 = 3,50 = ATTIVATO, 51 = 12,5,52 = 13,5,50 = 6M, 51 = 15,4,52 = 16,2,50 = 1Y, 51 = 17,2,52 = 18,3

Lasciami provare. Non sto scrivendo codice C#, solo dare una panoramica del mio approccio

vorrei spezzare questo in 2 segmenti Chain1 = {P0, P1} e {Chain2 = P2 ......} PN

pausa uniformemente la catena 2 in base al valore di P1. in base alla posizione della virgola.

substr=Chain.substring(0,Chain2.IndexOf(",", P1=3)); 

Siamo in grado di creare una collezione Tuple Classe -

here either i can use regex to split the string or simple substring and indexof("=") to extract value 

var seg= new Tuple<string, int, int, >("ON", 12.5, 13.5); 
Problemi correlati