2010-06-29 7 views
5

Ho il seguente metodo che ho creato che funziona bene se effettivamente c'è il delimitatore in questione. Voglio tenerlo fuori da LINQ per ora ...Metodo Split Split Method Problema quando non sono inclusi i delimitatori

ad es.

Se passo nella stringa "123; 322; 323" funziona alla grande.

Ma se passo solo un valore di stringa senza il delimitatore come "123" ovviamente non lo dividerò poiché non c'è delimitatore. Sto solo cercando di capire il modo migliore per controllare e conto di questo ed essere in grado di sputare che un valore di nuovo nella lista

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new List<int>(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    string[] values = stringToSplit.Split(splitDelimiter); 

    if (values.Length < 1) 
     return list; 

    foreach (string s in values) 
    { 
     int i; 
     if (Int32.TryParse(s, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

aggiornamento: Questo è ciò che mi si avvicinò con che sembra funzionare, ma certo è lunga

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
    { 
     List<int> list = new IntList(); 

     if (string.IsNullOrEmpty(stringToSplit)) 
      return list; 

     if (stringToSplit.Contains(splitDelimiter.ToString())) 
     { 
      string[] values = stringToSplit.Split(splitDelimiter); 

      if (values.Length <= 1) 
       return list; 

      foreach (string s in values) 
      { 
       int i; 
       if (Int32.TryParse(s, out i)) 
        list.Add(i); 
      } 
     } 
     else if (stringToSplit.Length > 0) 
     { 
      int i; 
      if(Int32.TryParse(stringToSplit, out i)) 
       list.Add(i); 
     } 

     return list; 
    } 
+0

Hai mai provato questo? – Marc

+0

Oppure lo ha debugato? – tster

+0

Sì, non l'ho postato a meno che non l'abbia debugato. – PositiveGuy

risposta

2

Ci sono MOLTI controlli non necessari per condizioni che non sono rilevanti per la logica di base del metodo.

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new IntList(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    //this if is not necessary. As others have said, Split will return a string[1] with the original string if no delimiter is found 
    if (stringToSplit.Contains(splitDelimiter.ToString())) 
    { 
     string[] values = stringToSplit.Split(splitDelimiter); 

     //why check this? if there are no values, the foreach will do nothing and fall through to a return anyway. 
     if (values.Length <= 1) 
      return list; 

     foreach (string s in values) 
     { 
      int i; 
      if (Int32.TryParse(s, out i)) 
       list.Add(i); 
     } 
    } 
    //again, this is rendered redundant due to previous comments 
    else if (stringToSplit.Length > 0) 
    { 
     int i; 
     if(Int32.TryParse(stringToSplit, out i)) 
      list.Add(i); 
    } 

    return list; 
} 

Prova questo. Si si spera che abbia qualche unit test che chiami questo metodo per assicurarsi che funzioni ... giusto?

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    List<int> list = new IntList(); 

    if (string.IsNullOrEmpty(stringToSplit)) 
     return list; 

    foreach(var s in stringToSplit.Split(splitDelimiter)) 
    { 
     int i; 
     if(int.TryParse(s, out i)) 
      list.Add(i); 
    } 
    return list; 
} 
+0

Grazie mille. Questo è un buon feedback e sì sto cercando di ridurre il mio codice non necessario in generale ...questa è stata una bella discussione per capire quanto disordine ci fosse dentro. Inizialmente non l'ho visto io stesso. – PositiveGuy

+0

Grazie per avermi ricordato dei test unitari. Il problema è che lavoro in un codice e gestisco un negozio in cui la qualità non è in prima linea, quindi non trovo tempo. Se ho il mio capo che mi respira il collo affermando che "non deve essere perfetto" o "che è fuori bordo" quando sto semplicemente cercando di creare un semplice codice pulito riutilizzabile, ciò non lascia spazio per il test dell'unità. "Trova il tempo allora" ... di nuovo, il capo continua a fare il check-in, vuole questo spinto, questo non è nel mio controllo. Lo stesso vecchio problema, lo sviluppo sono i negozi di sudore in molti casi, il caos, la spazzatura. È una delle ragioni per cui odio il mio lavoro a volte. – PositiveGuy

+0

@coffeeaddict, il testing delle unità ti consentirà di svilupparti più rapidamente, quindi non essere in grado di "trovare il tempo" per scrivere i test non è una scusa dato che le funzionalità saranno più lente senza test di unità. – tster

4

Cambiamento questa condizione:

if (values.Length <= 1) 
    return list; 

A:

if (values.Length <= 0) 
    return list; 

Questo funziona perché String.Split restituirà la stringa originale, se non riesce a trovare il delimitatore:

// stringToSplit does not contain the splitDelimiter 
string[] values = stringToSplit.Split(splitDelimiter); 
// values is a string array containing one value - stringToSplit 
+0

In alternativa, 'if (! Values.Any())', ma +1 per trovare il bug e la spiegazione di cosa '.Split' sta facendo per lui. – Marc

+0

se Split restituisce la stringa originale se non è possibile trovare il delimitatore allora value.Length dovrebbe essere 1 giusto? (e l'elemento è ai valori [0]) Il controllo di <= 1 è quindi corretto. – RvdK

+0

@PowerRoy - Sta cercando di verificare se l'array è vuoto e restituisce una lista vuota (leggi l'intero codice). L'array è vuoto quando non ci sono elementi in esso ('values.Length <= 0'). – Oded

0

Un'implementazione più breve si potrebbe prendere in considerazione.

public static List<int> StringToList(string stringToSplit, char splitDelimiter) 
{ 
    int i; 
    return stringToSplit.Split(splitDelimiter) 
     .Where(str => int.TryParse(str, out i)) 
     .Select(str => int.Parse(str)) 
     .ToList(); 
} 
+1

Non 'i' finirà per essere l'ultima stringa parse-able? Imo, effetti collaterali nei predicati linq = puzzolenti. – Marc

+0

a chi importa cosa io sia finito? È solo lì per permettermi di chiamare TryParse. – tster

+0

non ti permetterebbe di sostituire il .Select (str => int.Parse (str)) con .Select (str => i) – JDunkerley

0

O deve avere un delimitatore o, si parte deve avere una lunghezza fissao, la stringa deve seguire un modello per comportamento ripetizione.

+0

Non so cosa porterà la querystring nel senso che sto passando un valore querystring come stringToSplit. Sto chiamando questo metodo su un valore di querystring per dividerlo in una lista e dipende solo, a volte può avere uno, a volte più di uno in entrata (diviso per a;) quindi devo tenere conto di ogni situazione ... 1 o 1 a molti – PositiveGuy

1

Personalmente, non ho provato il codice, ma sembra funzionale. Il metodo Split dovrebbe restituire un array con un elemento.

Dal momento che si dice che non è, ti credo, e vorrei aggiungere questo alla parte superiore del metodo:

if (!stringToSplit.Contains(splitDelimiter)) 
{ 
    int i; 
    if (Int32.TryParse(stringToSplit, out i)) 
     list.Add(i); 
    return list; 
} 
1

Non è necessario per tenere conto di questa situazione, come string.Split() restituisce un array con un singolo elemento se non si trova delimitatore:

If this instance does not contain any of the strings in separator, the returned array consists of a single element that contains this instance.

Vedi msdn a "Osservazioni"

+0

scusa, a quali linee di codice ti riferisci? – PositiveGuy

+0

Ok, ma voglio aggiungere il valore singolo alla lista PositiveGuy

+0

Quindi stai dicendo list.Add (string.Split (';')) ?? Non seguo lo – PositiveGuy

1

Potrei suggerire un metodo di estensione per aiutarti in casi come questo in generale?

L'idea sarebbe di yield return tutti i risultati di una raccolta di stringhe che possono essere analizzate in un tipo specificato.

Prima avresti bisogno di un delegato per abbinare la firma del tuo TryParse metodo standard:

public delegate bool Parser<T>(string input, out T value); 

Quindi è possibile scrivere un metodo di estensione che prende un'istanza di questo tipo delegato e enumera su un insieme di stringhe , l'analisi ovunque si può:

// Notice: extension methods must belong to a class marked static. 
public static class EnumerableParser 
{ 
    // modified code to prevent horizontal overflow 
    public static IEnumerable<T> ParseAll<T> 
    (this IEnumerable<string> strings, Parser<T> parser) 
    { 
     foreach (string str in strings) 
     { 
      T value; 
      if (parser(str, out value)) 
       yield return value; 
     } 
    } 
} 

Ora il metodo di StringToList diventa banale da implementare:

public List<int> StringToList(string stringToSplit, char delimiter) 
{ 
    // Notice: since string.Split returns a string[], and string[] implements 
    // IEnumerable<string>, so the ParseAll extension method can be called on it. 
    return stringToSplit.Split(delimiter).ParseAll<int>(int.TryParse).ToList(); 
} 
+0

Esattamente, questa è la scelta naturale che dà il maggior senso in termini di manutenibilità e riutilizzo. Comunque BOSS, un dittatore fino al punto di voler usare anche List e mi obbliga ad usare la sua classe personalizzata IntList: Lista solo per non dover digitare anche non vuole usare i metodi di estensione (sì, io odio questo posto). Se discuto con lui mi farà licenziare. Non sto scherzando. – PositiveGuy

+0

Dove stai mettendo quel metodo in modo che sia un "metodo di estensione" e quindi rilevato da intellisense come un metodo fuori dallo split? – PositiveGuy

+0

quando hai chiamato ParseAll, vedo che stai passando solo il delegato. Ma come stai passando le stringhe param? – PositiveGuy