Коллекции C#

C Sharp > Коллекции C#
28.10.2016 15:25:31


Наиболее часто встречающиеся слова в статье:

[Element] [Collections] [Console] [theElement] [коллекции] [salmons] [объектов] [коллекцию] [elements] [foreach]


Статья:

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

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

В следующем примере создается список строк, а затем просматриваются строки

// Create a list of strings. 
var salmons = new List<string>();
salmons.Add("chinook");
salmons.Add("coho");
salmons.Add("pink");
salmons.Add("sockeye");

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

 

Следующий пример аналогичен предыдущему за исключением того, что инициализатор коллекции используется для добавления элементов в коллекцию.

// Create a list of strings by using a 
// collection initializer. 
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook coho pink sockeye

 

В следующем примере выполняется перебор элементов коллекции с помощью For…Next вместо For Each.

// Create a list of strings by using a 
// collection initializer. 
var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

for (var index = 0; index < salmons.Count; index++)
{
    Console.Write(salmons[index] + " ");
}
// Output: chinook coho pink sockeye

 

Следующий пример удаляет элемент из коллекции путем указания объекта для удаления.

var salmons = new List<string> { "chinook", "coho", "pink", "sockeye" };

// Remove an element from the list by specifying 
// the object.
salmons.Remove("coho");

// Iterate through the list. 
foreach (var salmon in salmons)
{
    Console.Write(salmon + " ");
}
// Output: chinook pink sockeye

 

В следующем примере удаляются элементы из универсального списка. 

var numbers = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

// Remove odd numbers. 
for (var index = numbers.Count - 1; index >= 0; index--)
{
    if (numbers[index] % 2 == 1)
    {
        // Remove the element by specifying 
        // the zero-based index in the list.
        numbers.RemoveAt(index);
    }
}

// Iterate through the list. 
// A lambda expression is placed in the ForEach method 
// of the List(T) object.
numbers.ForEach(
    number => Console.Write(number + " "));
// Output: 0 2 4 6 8

 

Для типа элементов в List можно также определить собственный класс. В следующем примере класс Galaxy, который используется объектом List, определен в коде.

private void IterateThroughList()
{
    var theGalaxies = new List<Galaxy>
        {
            new Galaxy() { Name="Tadpole", MegaLightYears=400},
            new Galaxy() { Name="Pinwheel", MegaLightYears=25},
            new Galaxy() { Name="Milky Way", MegaLightYears=0},
            new Galaxy() { Name="Andromeda", MegaLightYears=3}
        };

    foreach (Galaxy theGalaxy in theGalaxies)
    {
        Console.WriteLine(theGalaxy.Name + "  " + theGalaxy.MegaLightYears);
    }

    // Output: 
    //  Tadpole  400 
    //  Pinwheel  25 
    //  Milky Way  0 
    //  Andromeda  3
}

public class Galaxy
{
    public string Name { get; set; }
    public int MegaLightYears { get; set; }
}

 

 

Многие типовые коллекции предоставляются платформой .NET Framework. Каждый тип коллекции предназначен для определенной цели.

Следующие группы классов коллекций описаны в этом разделе:

  • Классы System.Collections.Generic

  • Классы System.Collections.Concurrent

  • Классы System.Collections

  • Класс Collection в Visual Basic

Универсальную коллекцию можно создать, используя один из классов в пространстве имен System.Collections.Generic. Универсальная коллекция применяется в том случае, если все элементы в коллекции имеют одинаковый тип данных. Универсальная коллекция обеспечивает строгую типизацию, позволяя добавление только необходимых типов данных.

В следующей таблице перечислены некоторые из часто используемых классов пространства имен System.Collections.Generic:

Класс

Описание

Dictionary

Предоставляет коллекцию пар ключ/значение, которые упорядочены по ключу.

List

Представляет список объектов, доступных по индексу. Предоставляет методы для поиска по списку, выполнения сортировки и изменения списка.

Queue

Предоставляет коллекцию объектов, которая обслуживается по принципу "первым пришел — первым вышел" (FIFO).

SortedList

Представляет коллекцию пар ключ/значение, упорядоченных по ключу на основе реализации IComparer.

Stack

Представляет коллекцию объектов, которая обслуживается по принципу "последним пришел — первым вышел" (LIFO).


Классы в пространстве имен System.Collections не хранят элементы в виде конкретно типизированных объектов, а хранят их как объекты типа Object.

Везде, где это возможно, следует использовать универсальные коллекции пространства имен System.Collections.Generic или пространства имен System.Collections.Concurrent вместо устаревших типов пространства имен System.Collections.

В следующей таблице перечислены некоторые из часто используемых классов в пространстве имен System.Collections:

Класс

Описание

ArrayList

Представляет массив объектов, размер которого динамически увеличивается по мере необходимости.

Hashtable

Предоставляет коллекцию пар ключ/значение, которые упорядочены по хэш-коду ключа.

Queue

Предоставляет коллекцию объектов, которая обслуживается по принципу "первым пришел — первым вышел" (FIFO).

Stack

Представляет коллекцию объектов, которая обслуживается по принципу "последним пришел — первым вышел" (LIFO).

Пространство имен System.Collections.Specialized предоставляет специализированные строго типизированные классы коллекций, такие как коллекции строк, связанные списки и гибридные словари.


Реализация коллекции пар "ключ-значение"

В следующем примере создается коллекция Dictionary и последовательно перебирается словарь с помощью оператора For Each.

private void IterateThruDictionary()
{
    Dictionary<string, Element> elements = BuildDictionary();

    foreach (KeyValuePair<string, Element> kvp in elements)
    {
        Element theElement = kvp.Value;

        Console.WriteLine("key: " + kvp.Key);
        Console.WriteLine("values: " + theElement.Symbol + " " +
            theElement.Name + " " + theElement.AtomicNumber);
    }
}

private Dictionary<string, Element> BuildDictionary()
{
    var elements = new Dictionary<string, Element>();

    AddToDictionary(elements, "K", "Potassium", 19);
    AddToDictionary(elements, "Ca", "Calcium", 20);
    AddToDictionary(elements, "Sc", "Scandium", 21);
    AddToDictionary(elements, "Ti", "Titanium", 22);

    return elements;
}

private void AddToDictionary(Dictionary<string, Element> elements,
    string symbol, string name, int atomicNumber)
{
    Element theElement = new Element();

    theElement.Symbol = symbol;
    theElement.Name = name;
    theElement.AtomicNumber = atomicNumber;

    elements.Add(key: theElement.Symbol, value: theElement);
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

 

Использование LINQ для доступа к коллекции

В следующем примере выполняется запрос LINQ к универсальному List. Запрос LINQ возвращает другую коллекцию, содержащую результаты.

private void ShowLINQ()
{
    List<Element> elements = BuildList();

    // LINQ Query. 
    var subset = from theElement in elements
                 where theElement.AtomicNumber < 22
                 orderby theElement.Name
                 select theElement;

    foreach (Element theElement in subset)
    {
        Console.WriteLine(theElement.Name + " " + theElement.AtomicNumber);
    }

    // Output: 
    //  Calcium 20 
    //  Potassium 19 
    //  Scandium 21
}

private List<Element> BuildList()
{
    return new List<Element>
    {
        { new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
        { new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
        { new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
        { new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
    };
}

public class Element
{
    public string Symbol { get; set; }
    public string Name { get; set; }
    public int AtomicNumber { get; set; }
}

Сортировка коллекции

В методе ListCars оператор cars.Sort() сортирует список. Этот вызов метода SortList приводит к тому, что метод CompareToвызывается автоматически для объектов Car в List.

private void ListCars()
{
    var cars = new List<Car>
    {
        { new Car() { Name = "car1", Color = "blue", Speed = 20}},
        { new Car() { Name = "car2", Color = "red", Speed = 50}},
        { new Car() { Name = "car3", Color = "green", Speed = 10}},
        { new Car() { Name = "car4", Color = "blue", Speed = 50}},
        { new Car() { Name = "car5", Color = "blue", Speed = 30}},
        { new Car() { Name = "car6", Color = "red", Speed = 60}},
        { new Car() { Name = "car7", Color = "green", Speed = 50}}
    };

    // Sort the cars by color alphabetically, and then by speed 
    // in descending order.
    cars.Sort();

    // View all of the cars. 
    foreach (Car thisCar in cars)
    {
        Console.Write(thisCar.Color.PadRight(5) + " ");
        Console.Write(thisCar.Speed.ToString() + " ");
        Console.Write(thisCar.Name);
        Console.WriteLine();
    }

    // Output: 
    //  blue  50 car4 
    //  blue  30 car5 
    //  blue  20 car1 
    //  green 50 car7 
    //  green 10 car3 
    //  red   60 car6 
    //  red   50 car2
}

public class Car : IComparable<Car>
{
    public string Name { get; set; }
    public int Speed { get; set; }
    public string Color { get; set; }

    public int CompareTo(Car other)
    {
        // A call to this method makes a single comparison that is 
        // used for sorting. 

        // Determine the relative order of the objects being compared. 
        // Sort by color alphabetically, and then by speed in 
        // descending order. 

        // Compare the colors. 
        int compare;
        compare = String.Compare(this.Color, other.Color, true);

        // If the colors are the same, compare the speeds. 
        if (compare == 0)
        {
            compare = this.Speed.CompareTo(other.Speed);

            // Use descending order for speed.
            compare = -compare;
        }

        return compare;
    }
}

 

Определение пользовательской коллекции

Метод GetEnumerator возвращает экземпляр класса ColorEnumerator. ColorEnumerator реализует интерфейс IEnumerator, который требует, чтобы были реализованы свойство Current, метод MoveNext и метод Reset.

private void ListColors()
{
    var colors = new AllColors();

    foreach (Color theColor in colors)
    {
        Console.Write(theColor.Name + " ");
    }
    Console.WriteLine();
    // Output: red blue green
}


// Collection class. 
public class AllColors : System.Collections.IEnumerable
{
    Color[] _colors =
    {
        new Color() { Name = "red" },
        new Color() { Name = "blue" },
        new Color() { Name = "green" }
    };

    public System.Collections.IEnumerator GetEnumerator()
    {
        return new ColorEnumerator(_colors);

        // Instead of creating a custom enumerator, you could 
        // use the GetEnumerator of the array. 
        //return _colors.GetEnumerator();
    }

    // Custom enumerator. 
    private class ColorEnumerator : System.Collections.IEnumerator
    {
        private Color[] _colors;
        private int _position = -1;

        public ColorEnumerator(Color[] colors)
        {
            _colors = colors;
        }

        object System.Collections.IEnumerator.Current
        {
            get
            {
                return _colors[_position];
            }
        }

        bool System.Collections.IEnumerator.MoveNext()
        {
            _position++;
            return (_position < _colors.Length);
        }

        void System.Collections.IEnumerator.Reset()
        {
            _position = -1;
        }
    }
}

// Element class. 
public class Color
{
    public string Name { get; set; }
}

 

Итераторы

Итератор используется для выполнения пользовательских итераций по коллекции. Итератор может быть методом или методом доступаget. Итератор использует оператор Yield (Visual Basic) или yield return (C#) для возврата каждого элемента коллекции по одному за раз.

Итератор вызывается с помощью оператора For Each…Next (Visual Basic) или foreach (C#). Каждая итерация цикла For Each вызывает итератор. При достижении оператора Yield или yield return в итераторе возвращается выражение, и текущее расположение в коде сохраняется. При следующем вызове итератора выполнение возобновляется с этого места.

Для получения дополнительной информации см. Итераторы (C# и Visual Basic).

В следующем примере используется метод-итератор. Метод-итератор содержит оператор Yield или yield return, который находится внутри цикла For…Next (Visual Basic) или for (C#). В методе ListEvenNumbers каждая итерация тела оператора For Each создает вызов метода-итератора, который переходит к следующему оператору Yield или yield return.

private void ListEvenNumbers()
{
    foreach (int number in EvenSequence(5, 18))
    {
        Console.Write(number.ToString() + " ");
    }
    Console.WriteLine();
    // Output: 6 8 10 12 14 16 18
}

private static IEnumerable<int> EvenSequence(
    int firstNumber, int lastNumber)
{
    // Yield even numbers in the range. 
    for (var number = firstNumber; number <= lastNumber; number++)
    {
        if (number % 2 == 0)
        {
            yield return number;
        }
    }
}