Domanda

c'è un modo in .NET (o una sorta di metodi di estensione standard) di porre domande su un elenco?

Ad esempio, l'elemento corrente è il primo o l'ultimo elemento dell'enumerazione:

string s = "";

foreach (var person in PeopleListEnumerator) {

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

  s += person.ToString();

  if (!PeopleListEnumerator.IsLastItem) s += ",";
  else s += "]";
}
È stato utile?

Soluzione

Solo per divertimento, una soluzione al problema generale che non richiede una valutazione entusiasta e ha una singola variabile locale (tranne l'enumeratore):

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

Prova:

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

Altri suggerimenti

Se la tua raccolta è un elenco, puoi fare:

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

Non che io sappia. Puoi provare a scrivere questi metodi di estensione da solo, però. Oppure tieni traccia del primo / ultimo elemento altrove.

Eric Lippert ha pubblicato un post sul blog su quel tipo di problema recentemente insieme ad alcune considerazioni su come modificare la descrizione del problema in modo da riflettere in modo più accurato ciò che si desidera effettivamente.

Probabilmente stai meglio usando un String.Join con alcuni LINQ in questo caso:

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

L'interfaccia IEnumerable non definisce o prevede che gli elementi che restituisce siano in un dato ordine. Quindi il concetto di & Quot; Primo & Quot; non sempre si applica.

Tuttavia, per questo particolare schema, questo è quello che faccio

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 ha scritto Smart Enumerations per fornire questo tipo di funzionalità e fanno parte della MiscUtils .

Detto questo, il tuo esempio specifico è meglio risolto dall'approccio String.Join () come molti altri hanno sottolineato. Scrivere un'estensione string Join(this IEnumerable<T>,string) generale non è difficile ed è quindi utilizzabile in altre situazioni senza dover ricorrere a fastidiose matrici temporanee.

Usando LINQ, puoi fare:

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

Mi trovo a definire e usare una citazione &; prenota prima " variabile locale, ad esempio:

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

foreach (var person in PeopleListEnumerator) {

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

Questo codice corrisponde strettamente a ciò che vuoi veramente realizzare:

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

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

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

Il modo in cui avrei scuoiato questo gatto (sì, ci sono molti modi) sarebbe:

StringBuilder sb = new StringBuilder();

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

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

Spero che questo aiuti ...

In .NET le enumerazioni non hanno alcun concetto di ordine, tranne che per valore. Se si desidera una prima e ultima enumerazione, suggerirei di definire esplicitamente quali sono questi primi e ultimi valori. La seguente enumerazione ne è un esempio:

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

Puoi quindi esprimere qualcosa di simile al seguente:

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

PlayerType starter = (PlayerType)values.Min();
PlayerType closer = (PlayerType)values.Max();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top