10 분 소요

이 글은 한빛미디어의 이것이 C#이다를 보고 헷갈리는 부분 위주로 정리한 글입니다.

배열의 선언

데이터_형식[] 배열_이름 = new 데이터_형식[용량];

// 용량이 5개인 int 형식의 배열
int[] scores = new int[5];

// 주의할 점은 배열의 인덱스는 0부터 시작
scores[0];
scores[1];
scores[2];
scores[3];
scores[4];
//scores[5]; 존재하지 않음, 호출시 에러 발생

^ 연산자 ( C# 8.0 이상) System.Index

^연산자를 이용하여 컬렉션의 마지막부터 역순으로 인덱스를 지정하는 기능.

int[] scores = new int[5] {0,1,2,3,4};
Console.WriteLine(scores[^1]); // 4 출력
// scores[scores.Length-1]과 같다고 볼 수 있음

배열의 초기화 세가지 방법

int[] scores1 = new int[3] { 0, 1, 2 }; // 정석
int[] scores2 = new int[] { 0, 1, 2 }; // 용량을 생략
int[] scores3 = { 0, 1, 2 }; // new 연산자, 형식, 용량 모두 생략

System.Array

정적 메소드

Sort() : 배열을 정렬합니다.

BinarySearch<T>() : 이진 탐색을 수행합니다.

IndexOf() : 배열에서 찾고자 하는 특정 데이터의 인덱스를 반환합니다.

TrueForAll<T>() : 배열의 모든 요소가 지정한 조건에 부합하는지 여부를 반환합니다.

trueforall 메소드는 배열과 함께 조건을 검사하는 메소드를 매개변수를 받습니다.

FindIndex<T>() : 특정 조건에 부합하는 첫 번째 요소의 인덱스를 반환합니다.

Resize<T>() : 배열의 크기를 재조정합니다.

Clear() : 배열의 모든 요소를 초기화합니다. (숫자 형식이면 모두 0으로 논리 형식이면 모두 false로 참조 형식이면 null 로 초기화)

ForEach<T>() : 배열의 모든 요소에 대해 동일한 작업을 수행하게 합니다.

Copy<T>() : 배열의 일부를 다른 배열에 복사합니다.

인스턴스 메소드

GetLength() : 배열에서 지정한 차원의 길이를 반환합니다. (다차원 배열에서 유용)

프로퍼티

Length : 배열의 길이 반환

Rank : 배열의 차원 반환

예제

private static bool CheckPassed(int score)
{
    return score >= 60;
}

private static void Print(int value)
{
    Console.Write($"{value} ");
}
static void Main(string[] args)
{
    int[] scores = new int[] { 80, 74, 81, 90, 34 };

    foreach (int score in scores)
    {
        Console.Write($"{score} ");
    }
    Console.WriteLine();

    Array.Sort(scores);
    // 배열의 모든 요소에 대해 동일한 작업을 수행하게 함
    Array.ForEach<int>(scores, new Action<int>(Print));
    Console.WriteLine();

    Console.WriteLine($"Number of dimensions : {scores.Rank}"); // 배열의 차원 반환

    Console.WriteLine($"Binary Search : 81 is at " +
        $"{Array.BinarySearch<int>(scores, 81)}"); // 이진 탐색을 수행

    Console.WriteLine($"Linear Search : 90 is at " +
        $"{Array.IndexOf<int>(scores, 90)}");
    // 배열에서 찾고자 하는 특정 데이터의 인덱스를 반환

    Console.WriteLine($"Everyone passed ? : " +
        $"{Array.TrueForAll<int>(scores, CheckPassed)}"); // 메소드를 매개변수로 받음
                                                          // 배열의 모든 요소가 지정한 조건에 부합하는지 여부를 반환

    // 특정 조건에 부합하는 첫 번째 요소의 인덱스를 반환합니다.
    int index = Array.FindIndex<int>(scores, (score) => score < 60); // 메소드를 매개변수로 받음

    scores[index] = 61;
    Console.WriteLine($"Everyone passed ? : " +
        $"{Array.TrueForAll<int>(scores, CheckPassed)}");

    Console.WriteLine("Old length of scroes : " +
        $"{scores.GetLength(0)}"); // 배열에서 지정한 차원의 길이를 반환

    Array.Resize<int>(ref scores, 10); // 배열의 크기를 재조정, 여기서는 5 -> 10
    Console.WriteLine($"New length of scores : {scores.Length}");

    Array.ForEach<int>(scores, new Action<int>(Print));
    Console.WriteLine();

    Array.Clear(scores, 3, 7); // 배열의 모든 요소를 초기화 3번째 방부터 7개를 초기화
    Array.ForEach<int>(scores, new Action<int>(Print));
    Console.WriteLine();

    int[] sliced = new int[3];
    Array.Copy(scores, 0, sliced, 0, 3);
    // score의 0부터 3개 요소를 sliced의 0부터 3개 요소에 복사
    Array.ForEach<int>(sliced, new Action<int>(Print));
    Console.WriteLine();
}

// 출력 결과
80 74 81 90 34
34 74 80 81 90
Number of dimensions : 1
Binary Search : 81 is at 3
Linear Search : 90 is at 4
Everyone passed ? : False
Everyone passed ? : True
Old length of scroes : 5
New length of scores : 10
61 74 80 81 90 0 0 0 0 0
61 74 80 0 0 0 0 0 0 0
61 74 80

배열 분할하기 C# 0.8이상

분할에 대해 알알보기전에 알아둘 것은

System.Index 형식과 함께 도입된 System.Range

.. 사용하여 배열의 범위를 나타냄 
System.Range range = 1..5; // 1번째 부터 ~ "5번째 전 까지"
// 위 처럼 주의 마지막 인덱스는 배열 분할 결과에서 제외됨

// 예시
int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
foreach (int i in a[range]) // a[1..5] 도 가능
{
		Console.WriteLine(i);
}
// 출력
// 2
// 3
// 4
// 5

시작 인덱스와 끝 인덱스를 생략하거나

System.Index 객체를 이용할 수도 있다.

System.Range range1 = ..5; // 처음부터 4 까지 
System.Range range2 = 3..; // 3부터 끝 까지 
System.Range range3 = ..; // 처음부터 끝까지 

System.Index idx = ^1;
System.Range range4 = ..idx; // 처음 부터 끝 전 방까지
System.Range range5 = ^4..^1; // 끝에서 4번째 방부터 끝 바로 전 방 까지
static void PrintArray(System.Array array)
        {
            foreach (var item in array) 
                Console.Write(item);
            Console.WriteLine();
        }
        static void Main(string[] args)
        {
            // 알파벳 개수만큼 만듬
            char[] array = new char['Z' - 'A' + 1]; //ASCII코드로 Z = 90 A = 65 즉 26
            for (int i = 0; i < array.Length; i++)
                array[i] = (char)('A' + i);

            PrintArray(array[..]); // 첨부터 끝까지
            PrintArray(array[5..]); // 5부터 끝까지

            Range range_5_10 = 5..10;
            PrintArray(array[range_5_10]); // 5부터 9까지

            Index Last = ^0; // 끝 + 1 번째
            Range range_5_last = 5..Last;
            PrintArray(array[range_5_last]); // 5부터 끝까지

            PrintArray(array[^4..^1]); // 끝에서 4번째 부터 끝에서 2번째
        }
//ABCDEFGHIJKLMNOPQRSTUVWXYZ
//FGHIJKLMNOPQRSTUVWXYZ
//FGHIJ
//FGHIJKLMNOPQRSTUVWXYZ
//WXY

2차원 배열

1차원 배열을 원소로 같는 배열

기본적으론 1차원 배열과 선언 형식이 같지만 각 차원의 용량 또는 길이를 콤마(,)로 구분해서

대괄호 사이에 입력해줌.

데이터_형식[,] 배열이름 = new 데이터_형식[2차원_길이, 1차원_길이];

2차원 배열의 초기화

int[,] array = new int[2, 3] { { 0, 1, 2 }, { 3, 4, 5 } }; // 기본
int[,] array = new int[,] { { 0, 1, 2 }, { 3, 4, 5 } }; // 배열의 길이 생략
int[,] array ={ { 0, 1, 2 }, { 3, 4, 5 } }; // 형식과 길이 모두 생략

예시

static void Main(string[] args)
{
    int[,] arr = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };

    Console.WriteLine("arr");

    for (int i = 0; i < arr.GetLength(0); i++)
    {
        for (int j = 0; j < arr.GetLength(1); j++)
        {
            Console.Write($"[{i}, {j}] : {arr[i, j]} ");
        }
        Console.WriteLine();
    }
    Console.WriteLine();

    int[,] arr2 = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } };

    Console.WriteLine("arr2");

    for (int i = 0; i < arr2.GetLength(0); i++)
    {
        for (int j = 0; j < arr2.GetLength(1); j++)
        {
            Console.Write($"[{i}, {j}] : {arr2[i, j]} ");
        }
        Console.WriteLine();
    }
    Console.WriteLine();

    int[,] arr3 = new int[,] { { 1, 2, 3 }, { 4, 5, 6 } };

    Console.WriteLine("arr3");

    for (int i = 0; i < arr3.GetLength(0); i++)
    {
        for (int j = 0; j < arr3.GetLength(1); j++)
        {
            Console.Write($"[{i}, {j}] : {arr3[i, j]} ");
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

다차원 배열

2차원 이상의 배열들 모두가 다차원배열

2차원은 1차원 배열을 원소로 갖는 다차원

3차원은 2차원 배열을 원소로 갖는 다차원

4차원은 3차원 배열을 원소로 갖는 다차원

static void Main(string[] args)
{
    int[] array1 = new int[2]; // 1차원

    int[,] array2 = new int[3, 2] { { 1, 2 }, { 3, 4 }, { 5, 6 } }; // 2차원

    int[,,] array3 = new int[4, 3, 2] // 3차원
    {
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} }
    };

    int[,,,] array4 = new int[2, 4, 3, 2] // 4차원
    { { 
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} }
    },
    {
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} },
        { { 1, 2}, { 3 ,4}, { 5, 6} }
    } };
}

가변 배열

데이터_형식[][] 배열_이름 = new 데이터_형식[가변_배열의_용략][];

다른 다차원 배열과 비슷하지만 이 배열은 배열의 요소로 입력되는 배열의 크기가

다 같을 필요가 없음.

int[][] array1 = new int[3][];

    array1[0] = new int[3];
    array1[1] = new int[4];
    array1[2] = new int[5];

컬렉션 맛보기

ArrayList

가장 배열과 닮은 컬렉션.

Add, RemoveAt, Insert 등을 사용함.

데이터를 담을때 박싱을, 데이터를 꺼낼때 언박싱을 하여

다양한 형식의 객체를 담을 수 있다.

using System.Collections;

static void Main(string[] args)
{
    ArrayList list = new ArrayList();
    for (int i = 0; i < 5; i++)
        list.Add(i);

    foreach (object obj in list)
        Console.Write($"{obj} ");
    Console.WriteLine();

    list.RemoveAt(0);

    foreach (object obj in list)
        Console.Write($"{obj} ");
    Console.WriteLine();

    list.Insert(2, 2);

    foreach (object obj in list)
        Console.Write($"{obj} ");
    Console.WriteLine();

    list.Add("abc"); // 문자열도 담긴다
    list.Add("def");

    for (int i = 0; i < list.Count; i++)
        Console.Write($"{list[i]}");
    Console.WriteLine();
}
//0 1 2 3 4
//1 2 3 4
//1 2 2 3 4
//12234abcdef

Queue

데이터나 작업을 차례대로 입력해둔 뒤 순서대로 하나씩 꺼내 처리하기 위해 사용됨.

입력은 뒤로만 출력은 앞으로만 가능하다.

Enqueue() 메소드를 통해 입력

Dequeue() 메소드를 통해 출력

예시

static void Main(string[] args)
{
    Queue queue = new Queue();
    queue.Enqueue(1);
    queue.Enqueue(2);
    Console.WriteLine(queue.Dequeue()); // 1이 출력됨
    Console.WriteLine(queue.Dequeue()); // 다음으로 입력된 2가 출력됨
}
//1
//2

Stack

stack은 queue와 반대로 나중에 들어온 데이터가

가장 먼저 출력된다. 먼저 입력된 데이터는 가장 나중에 뽑힌다. push()를 통해 데이터를 넣고

Pop() 을 통해 데이터를 꺼냄

예시

static void Main(string[] args)
{
    Stack stack = new Stack();
    stack.Push(1);
    stack.Push(2);
    Console.WriteLine(stack.Pop());
    Console.WriteLine(stack.Pop());
}
//2
//1

hashtable

키와 값의 쌍으로 이루어진 데이터를 다룰 때 사용

키를 사용하여 검색하여 데이터를 찾기에 인덱스를 이용하여 배열 요소에 접근하는 것에

준하는 탐색 속도를 자랑함.

배열이 인덱스를 사용하는 방식처럼 [ ] 사이에 키를 넣어주어 입력, 출력 함

예시

static void Main(string[] args)
{
    Hashtable ht = new Hashtable();
    ht["하나"] = 1;
    ht["둘"] = 2;
    ht["셋"] = 3;

    Console.WriteLine(ht["하나"]);
    Console.WriteLine(ht["셋"]);
    Console.WriteLine(ht["둘"]);
}         

컬렉션을 초기화하는 방법

  • arraylist, queue, stack은 배열의 도움을 받아 초기화 가능
static void Main(string[] args)
{
    int[] array = { 123, 456, 789 };

    ArrayList list = new ArrayList(array); // 123, 456, 789
    Queue queue = new Queue(array); // 123, 456, 789
    Stack stack = new Stack(array); // 123, 456, 789
}
  • arratList는 직접 컬렉션 초기자를 이용해 초기화 할 수 있음
ArrayList list = new ArrayList() { 123, 456, 789 };
  • hashtable은 딕셔너리 초기자를 이용하여 초기화, 컬렉션 초기자를 통한 초기화가 있음
Hashtable htD = new Hashtable() // 딕셔너리 초기자
{
        ["하나"] = 1,
        ["둘"] = 2,
        ["셋"] = 3
} ;
Hashtable htC = new Hashtable() // 컬렉션 초기자
{
        {"하나", 1 },
        {"둘", 2 },
        {"셋", 3 }
};

인덱서 Indexer

인덱스를 이용해서 객체 내의 데이터에 접근하게 해주는 프로퍼티라고 생각하면 이해하기 쉬움

객체를 마치 배열처럼 사용할 수 있게 해줌.

class MyList
{
    private int[] array;

    public MyList()
    {
        array = new int[3];
    }

    public int this[int index]
    {
        get { return array[index]; }
        set
        {
            if (index >= array.Length)
            {
                Array.Resize<int>(ref array, index + 1);
                Console.WriteLine($"Array Resized : {array.Length}");
            }

            array[index] = value;
        }
    }
    public int Length
    {
        get { return array.Length; }
    }

    internal class Program
    {

        static void Main(string[] args)
        {
            MyList list = new MyList();
            for (int i = 0; i < 5; i++)
            {
                list[i] = i;
            }
            for (int i = 0; i < list.Length; i++)
                Console.WriteLine(list[i]);

        }
    }
}

foreach가 가능한 객체 만들기

foreach가 가능하기 위해선 인터페이스 IEnumerable을 상속해야함.

그러므로 IEnumerable이 가지고 있는 메소드를 구현해야 하는데 그것이 바

IEnumerator GetEnumerator() 메소드를 구현해야함

이 메소드는 IEnumerator 형식의 객체를 반환하기에 IEnumerator의 객체도 구현해야함

하지만 IEnumerator 를 상속하는 클래스를 따로 만들어 객체를 만들 필요없이

yield문을 이용할 수 있음.

yield return문은 현재 메소드의 실행을 일시 정지 해놓고 호출자에게 결과를 반환함

메소드가 다시 호출되면, 일시 정지된 실행을 복구하여 yield return 또는 yeild break 문을

만날 때 까지 나머지 작업을 실행하게 됨.

다음은 yield문을 사용하여 foreach가 가능한 객체를 만드는 예시임

using System.Collections;
class MyEnumerator
{
    int[] numbers = { 1, 2, 3, 4 };
    public IEnumerator GetEnumerator()
    {
        yield return numbers[0];
        yield return numbers[1];
        yield return numbers[2];
        yield break;
    }
}
internal class Program
{

    static void Main(string[] args)
    {
        var obj = new MyEnumerator();
        foreach (int i in obj)
        {
            Console.WriteLine(i);
        }
    }
}

// 정리
// foreach 문을 돌릴 수 있는 객체를 만들려면
// IEnumerator를 반환하는 GetEnumerator()를 구현하면 됨

IEnumerator를 직접 상속받아 구현할 수도 있다.

그 경우 IEnumerator의 메소드와 프로퍼티를 구현해야만한다

다음은 그 예시이다

using System.Collections;

class MyList : IEnumerable, IEnumerator
{
    private int[] array;
    int position = -1;

    public MyList()
    {
        array = new int[3];
    }

    public int this[int index]
    {
        get
        {
            return array[index];
        }

        set
        {
            if(index >= array.Length)
            {
                Array.Resize<int>(ref array, index + 1);
                Console.WriteLine($"Array Resized : {array.Length}");
            }

            array[index] = value;
        }
    }

    // IEnumerator 멤버
    // 현재 위치를 반환하는 프로퍼티
    public object Current
    {
        get
        {
            return array[position];
        }
    }

    // IEnumrator 멤버
	// 이동을 구현. 컬렉션의 끝을 지난 경우 false, 이동이 성공한 경우 true반환
    public bool MoveNext()
    {
        if(position == array.Length - 1)
        {
            Reset();
            return false;
        }

        position++;
        return (position < array.Length);
    }

    // IEnumerator 멤버
	// 첫 번째 위치의 '앞'으로 이동
    public void Reset()
    {
        position = -1;
    }

    // IEnumeraable 멤버
    public IEnumerator GetEnumerator()
    {
        return this; // 자신이 enumerator 이므로 yield문을 사용할 필요없이 자신을 반환
    }
}
internal class Program
{
    static void Main(string[] args)
    {
        MyList list = new MyList();
        for (int i = 0; i < 5; i++)
        {
            list[i] = i;
        }

        foreach (int e in list)
            Console.WriteLine(e);
    }
}

태그:

카테고리:

업데이트:

댓글남기기