2012-04-23 3 views
8

Ich habe die folgende Liste von verschiedenen Strings:Gibt es einen besseren Weg, um das nächste Element in einer Liste und Schleife vom Ende nach vorne zu bringen?

"A"
"B"
"C"

Wenn ich das Produkt nach der A möge, erhalte ich B. Nach B, Ich bekomme C. Nach C bekomme ich A. Zur Zeit habe ich den folgenden Code, aber aus irgendeinem Grund fühlt es sich für mich an, dass es einen besseren Weg gibt (vielleicht?).

private string GetNext(IList<string> items, string curr) 
{ 
    if (String.IsNullOrWhitespace(curr)) 
     return items[0]; 

    var index = items.IndexOf(curr); 
    if (index == -1) 
     return items[0]; 

    return (index + 1 == items.Count) ? items[0] : items[index + 1]; 
} 

Ich bin auf jeden Fall offen für eine LINQ-artige Möglichkeit, dies auch zu tun :)

+0

denke ich, dass dies: http://stackoverflow.com/questions/716256/creating-a-circually-linked-list-in-c ist was du suchst – hyp

+0

@hyp: Nun, das würde funktionieren, wenn der übergebene Parameter eine 'CircularLinkedList ' wäre, aber es ist nur ein 'IList '. –

Antwort

6

Ich denke, vielleicht können Sie die Zeile ändern

return (index + 1 == items.Count) ? items[0] : items[index + 1]; 

für so etwas wie

return items[(index + 1) % items.Count]; 
+1

Gute Verbesserung, ich nehme das. Obwohl es (Index + 1) richtig sein sollte? –

+0

Ich denke nicht, denn in Ihrem Array Count = 3 und wenn Sie Index = 3 erhalten, wird 3% 3 == 0 zurückgeben. Wenn Sie Index = 2 erhalten (um 'C' zurückzugeben) werden Sie es richtig machen 2% 3 = 2 – Andres

+0

Ja, Sie haben Recht. – Andres

0

Sie können den Mod-Operator verwenden, um dies ein wenig zu vereinfachen und alles in einer Anweisung zu kombinieren:

return items[((String.IsNullOrWhitespace(curr) 
       ? 0 
       : items.IndexOf(curr)) + 1) % items.Count] 

Sein definitiv kürzer, aber ich bin sicher nicht Wetter.Seine besser lesbar, auch :)

1

ich einige Optimierungen sehen kann, wenn Sie den aktuellen Index verfolgen, anstatt die aktuelle Zeichenfolge, aber das das zu tun Liste der Elemente müsste festgelegt werden, dh nicht ändern.

Sie könnten auch return items[(index + 1) % items.Count];

Ansonsten dass Code sieht für mich in Ordnung, aber vielleicht hat jemand eine clevere Lösung.

7

Die Lösung, die Sie haben, ist funktional korrekt, aber die Leistung lässt ein wenig zu wünschen übrig. Wenn Sie mit einer List-Stilstruktur arbeiten, würden Sie normalerweise erwarten, dass GetNext ein Ergebnis in O (1) -Zeit zurückgibt, aber diese Lösung ist O (N).

public sealed class WrappingIterator<T> { 
    private IList<T> _list; 
    private int _index; 
    public WrappingIterator<T>(IList<T> list, int index) { 
    _list = list; 
    _index = index; 
    } 
    public T GetNext() { 
    _index++; 
    if (_index == _list.Count) { 
     _index = 0; 
    } 
    return _list[_index]; 
    } 

    public static WrappingIterator<T> CreateAt(IList<T> list, T value) { 
    var index = list.IndexOf(value); 
    return new WrappingIterator(list, index); 
    } 
} 

Der erste Aufruf von CreateAt ist O (N) hier aber nachfolgende Aufrufe GetNext sind O (1).

IList<string> list = ...; 
var iterator = WrappingIterator<string>.CreateAt(list, "B"); 
Console.WriteLine(iterator.GetNext()); // Prints C 
Console.WriteLine(iterator.GetNext()); // Prints A 
Console.WriteLine(iterator.GetNext()); // Prints B 
+1

Dies ist eine sehr interessante Art und Weise zu gehen. Ein bisschen komplizierter als ich möchte, aber auf jeden Fall interessant. –

+0

Auch nur ein FYI. Der einzige Grund, warum ich diese Antwort nicht akzeptierte, ist, dass die Funktion eine 'IList 'einnimmt, und ich wollte keinen neuen Iterator für jeden Aufruf der Funktion erstellen. –

1

LINQ ist nicht das geeignete Werkzeug hier.

Es klingt, als ob ein LinkedList<T> die bessere Sammlung hier wäre:

var linkedItems = new LinkedList<String>(items); 
LinkedListNode current = linkedItems.Find("C"); 
String afterC = current.Next == null ? linkedItems.First.Value : current.Next.Value; 

Here die Vor- und Nachteile einer LinkedList im Vergleich zu einer Liste sind.

1

A Linq Weg:

var result = (from str in list 
       let index = list.IndexOf(curr) + 1 
       select list.ElementAtOrDefault(index) ?? list[0]).First(); 
Verwandte Themen