2012-04-23 22 views
8

tengo la siguiente lista de distintas cadenas:¿Hay una forma mejor de devolver el siguiente artículo en una lista y pasar del extremo al frente?

"A"
"B"
"C"

Si quiero el artículo después de una, me sale B. Después de B, Obtengo C. Después de C, obtengo A. Actualmente tengo el siguiente código, pero por alguna razón siento que hay una mejor manera de hacerlo (¿quizás?).

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

definitivamente estoy abierto a una forma de LINQ-esque de hacer esto, así :)

+0

creo que esto: es http://stackoverflow.com/questions/716256/creating-a-circually-linked-list-in-c lo que está buscando – hyp

+0

@hyp: Bueno, esto funcionaría si el parámetro que se pasa fuera un 'CircularLinkedList ', pero es simplemente un 'IList '. –

Respuesta

6

creo que tal vez puede cambiar la línea

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

para algo así como

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

Buena mejora, tomaré eso. Aunque debería ser (índice + 1) ¿verdad? –

+0

No lo creo, porque en su array Count = 3 y cuando obtiene Index = 3 devolverá 3% 3 == 0. Cuando obtenga index = 2 (para devolver 'C') lo hará bien 2% 3 = 2 – Andres

+0

Sí, tienes razón. – Andres

0

Puede usar el operador mod para simplificar esto un poco y combinar todo en una sola declaración:

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

Su definitivamente más cortos, pero no estoy seguro de tiempo es más legible, también :)

1

puedo ver algunos optimización si la pista del índice actual en lugar de la cadena actual, pero para hacer que la la lista de elementos debería ser fija, es decir, no cambiar.

Usted también podría return items[(index + 1) % items.Count];

lo contrario que el código se ve bien para mí, pero tal vez alguien tiene una solución más inteligente.

7

La solución que tiene es funcionalmente correcta, pero su rendimiento deja un poco que desear. Normalmente, cuando se trata de una estructura de estilo de lista, cabría esperar que GetNext devolviera un resultado en O (1) tiempo, pero esta solución es 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); 
    } 
} 

la llamada inicial a CreateAt es O (N) aquí, pero las posteriores llamadas a GetNext son 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

Esta es una forma muy interesante de hacerlo. Un poco más complicado de lo que me gustaría, pero definitivamente interesante. –

+0

Además, solo un FYI. La única razón por la que no acepté esta respuesta es porque la función toma un 'IList ', y no quería crear un nuevo iterador para cada llamada a la función. –

1

LINQ no es la herramienta adecuada aquí.

Suena como si un LinkedList<T> sería la mejor colección aquí:

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

Here son los pros y los contras de una LinkedList en comparación con una lista.

1

Una forma de LINQ:

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