перечисление .net первый и последний - PullRequest
4 голосов
/ 29 июня 2009

есть ли способ в .NET (или какие-то стандартные методы расширения) задавать вопросы перечисления?

Например, текущий элемент - первый или последний элемент в перечислении:

string s = "";

foreach (var person in PeopleListEnumerator) {

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

  s += person.ToString();

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

Ответы [ 10 ]

8 голосов
/ 29 июня 2009

Ради интереса решение общей проблемы, не требующее тщательной оценки и имеющее одну локальную переменную (кроме перечислителя):

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

Тест:

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);
        }
    }
}
3 голосов
/ 29 июня 2009

Если ваша коллекция представляет собой список, вы можете сделать:

string s = "[" + String.Join(",", PeopleList.ToArray()) + "]";
2 голосов
/ 29 июня 2009

Не то, что я знаю. Вы можете попробовать написать такие методы расширения самостоятельно. Или отслеживайте первый / последний элемент в другом месте.

У Эрика Липперта недавно было сообщение в блоге о такой проблеме, а также некоторые мысли о том, как изменить описание вашей проблемы, чтобы более точно отразить то, что вы действительно хотите.

Возможно, вам лучше использовать String.Join с некоторым LINQ в этом случае:

String.Join(
  ",",
  (from p in PeopleListEnumerator
  select p.ToString()).ToArray()
)
1 голос
/ 29 июня 2009

Джон Скит написал Умные перечисления , чтобы обеспечить такую ​​функциональность, и они являются частью библиотеки MiscUtils .

При этом ваш конкретный пример лучше всего решается с помощью подхода String.Join (), как отмечали многие другие. Написание общего расширения string Join(this IEnumerable<T>,string) не сложно, и его можно использовать в любых других ситуациях, не прибегая к надоедливым временным массивам.

1 голос
/ 29 июня 2009

Используя LINQ, вы можете сделать:

string s = 
    string.Format("[{0}]", string.Join(",",PeopleListEnumerator.Select(p => p.ToString()).ToArray()));
1 голос
/ 29 июня 2009

Интерфейс IEnumerable не определяет и не ожидает, что элементы, которые он возвращает, находятся в каком-либо заданном порядке. Так что понятие «Первый» не всегда применимо.

Тем не менее, для этого конкретного шаблона это то, что я делаю

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

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

result.Append( ']' );
0 голосов
/ 29 июня 2009

То, как я скину эту кошку (да, есть много способов), будет:

StringBuilder sb = new StringBuilder();

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

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

Надеюсь, это поможет ...

0 голосов
/ 29 июня 2009

Этот код близко соответствует тому, что вы действительно хотите выполнить:

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

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

return s.Append("]").ToString();
0 голосов
/ 29 июня 2009

В перечислениях .NET нет понятия порядка, кроме как по значению. Если вы хотите первое и последнее перечисление, я бы предложил явно определить, что это за первое и последнее значения. Следующее перечисление является примером этого:

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

Затем вы можете выразить нечто похожее на следующее:

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

PlayerType starter = (PlayerType)values.Min();
PlayerType closer = (PlayerType)values.Max();
0 голосов
/ 29 июня 2009

Я определяю и использую локальную переменную "bool first", например:

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

foreach (var person in PeopleListEnumerator) {

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