Pregunta

¿hay alguna manera en .NET (o algún tipo de método de extensión estándar) para hacer preguntas de una enumeración?

Por ejemplo, el elemento actual es el primer o el último elemento de la enumeración:

string s = "";

foreach (var person in PeopleListEnumerator) {

  if (PeopleListEnumerator.IsFirstItem) s += "[";

  s += person.ToString();

  if (!PeopleListEnumerator.IsLastItem) s += ",";
  else s += "]";
}
¿Fue útil?

Solución

Solo por diversión, una solución al problema general que no requiere una evaluación entusiasta y tiene una sola variable local (excepto el enumerador):

static class TaggedEnumerableExtensions
{
    public class TaggedItem<T>
    {
        public TaggedItem(T value, bool isFirst, bool isLast)
        {
            IsFirst = isFirst;
            IsLast = isLast;
            Value = value;
        }
        public T Value { get; private set; }
        public bool IsFirst { get; private set; }
        public bool IsLast { get; private set; }
    }
    public static IEnumerable<TaggedItem<T>> ToTaggedEnumerable<T>(this IEnumerable<T> e)
    {
        using (var enumerator = e.GetEnumerator()) {
            if (!enumerator.MoveNext())
                yield break;
            var current = enumerator.Current;
            if (!enumerator.MoveNext()) {
                yield return new TaggedItem<T>(current, true, true);
                yield break;
            } else {
                yield return new TaggedItem<T>(current, true, false);
            }

            for (;;) {
                current = enumerator.Current;
                if (!enumerator.MoveNext()) {
                    yield return new TaggedItem<T>(current, false, true);
                    yield break;
                }
                yield return new TaggedItem<T>(current, false, false);
            }
        }
    }
}

Prueba:

class Program
{
    static void Main(string[] args)
    {
        foreach (var item in Enumerable.Range(0, 10).ToTaggedEnumerable()) {
            Console.WriteLine("{0} {1} {2}", item.IsFirst, item.IsLast, item.Value);
        }
    }
}

Otros consejos

Si su colección es una Lista, puede hacer:

string s = "[" + String.Join(",", PeopleList.ToArray()) + "]";

No que yo sepa. Sin embargo, puede intentar escribir dichos métodos de extensión usted mismo. O realice un seguimiento del primer / último elemento en otro lugar.

Eric Lippert tuvo una publicación de blog sobre ese tipo de problema recientemente, junto con algunas ideas sobre cómo modificar la descripción de su problema para reflejar con mayor precisión lo que realmente quiere.

Probablemente sea mejor usar un String.Join con algo de LINQ en este caso:

String.Join(
  ",",
  (from p in PeopleListEnumerator
  select p.ToString()).ToArray()
)

La interfaz IEnumerable no define ni espera que los elementos que devuelve estén en un orden determinado. Entonces, el concepto de & Quot; Primero & Quot; no siempre se aplica.

Sin embargo, para este patrón en particular, esto es lo que hago

StringBuilder result = new StringBuilder();
result.Append( '[' );

foreach( var person in PeopleListEnumerator )
{
    if( result.Length > 1 )
        result.Append( ',' );
    result.Append( person.ToString() );
}

result.Append( ']' );

Jon Skeet escribió Smart Enumerations para proporcionar este tipo de funcionalidad y forman parte de la MiscUtils biblioteca.

Dicho esto, su ejemplo específico se resuelve mejor con el enfoque String.Join () como muchos otros han señalado. Escribir una extensión general string Join(this IEnumerable<T>,string) no es difícil y luego se puede usar en más situaciones sin tener que recurrir a molestos arreglos temporales.

Usando LINQ, puede hacer:

string s = 
    string.Format("[{0}]", string.Join(",",PeopleListEnumerator.Select(p => p.ToString()).ToArray()));

Me encuentro definiendo y usando una cita &; libro primero " variable local, por ejemplo:

string s = "[";
bool first = true;

foreach (var person in PeopleListEnumerator) {

  if (first)
    first = false;
  else
    s += ",";
  s += person.ToString();
}
s += "]";

Este código coincide estrechamente con lo que realmente quieres lograr:

StringBuilder s = new StringBuilder("[");
string delimiter = "";

foreach (var person in PeopleListEnumerator) {  
  s.Append(delimiter).Append(person.ToString());
  delimiter = ",";
}

return s.Append("]").ToString();

La forma en que pelaría a este gato (sí, hay muchas maneras) sería:

StringBuilder sb = new StringBuilder();

foreach (var person in PeopleListEnumerator )
{
    sb.AppendFormat(",{0}", person.ToString());
}

string s = "[" + sb.ToString().Substring(1) + "]";

Espero que esto ayude ...

En .NET las enumeraciones no tienen un concepto de orden, excepto por valor. Si desea una primera y última enumeración, sugeriría definir explícitamente cuáles son estos valores primero y último. La siguiente enumeración es un ejemplo de esto:

public enum PlayerType : byte
{
    Starter = byte.MinValue,
    RegularPlayer = 1,
    BenchWarmer = 2,
    Closer = byte.MaxValue
}

Luego puede expresar algo similar a lo siguiente:

List<byte> values = new List<byte>((byte[])Enum.GetValues(typeof(PlayerType)));

PlayerType starter = (PlayerType)values.Min();
PlayerType closer = (PlayerType)values.Max();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top