본문 바로가기
공부/C#

C# 공부(12) 111~124(Part3 End && C# 언어 공부 End)

by 라이티아 2024. 8. 28.

111. SortedList와 SortedList<TKey, TValue>

using System;
using System.Collections.Generic;

namespace P111
{
    class Program
    {
        static void Main(string[] args)
        {
            SortedList<int, string> s1 = new SortedList<int, string>();
            s1.Add(3, "C");
            s1.Add(4, "D");
            s1.Add(1, "A");
            s1.Add(2, "B");

            for (int i = 0; i < s1.Count; i++) Console.WriteLine(s1.Keys[i] + " " + s1.Values[i]);

            Console.WriteLine();

            foreach (var v in s1 ) Console.WriteLine(v);

            SortedList<string, int> s2 = new SortedList<string, int>();
            s2.Add("A", 1);
            s2.Add("B", 2);
            s2.Add("C", 3);
            s2.Add("D", 4);

            Console.WriteLine(s2["C"]);

            int val;
            if (s2.TryGetValue("A", out val)) Console.WriteLine("A : "+val);
            Console.WriteLine(s2.ContainsKey("C"));
            Console.WriteLine(s2.ContainsValue(2));

            s2.Remove("A");
            s2.RemoveAt(2);

            foreach (var v in s2) Console.WriteLine($"{v, -10}");
        }
    }
}

 

결과

1 A
2 B
3 C
4 D

[1, A]
[2, B]
[3, C]
[4, D]
3
A : 1
True
True
[B, 2]
[C, 3]

 

딕셔너리와 비슷하게 key와 value를 가진 클래스, SortedList이다.

코드가 보여주는 것은 사용법과, TryGetValue같은 매소드 들이다.

아이템창에서 퀘스트 아이템이 있는지 검사하는 매커니즘에 사용하면 좋을 것 같다.

 

112. 인덱서

using System;
namespace P112
{
    class MyCollection<T>
    {
        private T[] arr = new T[100];

        public T this[int i]
        {
            get { return arr[i]; }
            set { arr[i] = value; }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var myString = new MyCollection<string>();

            myString[0] = "A";
            myString[1] = "B";
            myString[2] = "C";

            for (int i = 0; i < 3 ; i++)
                Console.WriteLine(myString[i]);
        }
    }
}

 

결과

A

B

C

 

array를 프로그래머가 직접 구현하는 형태인 것 같다.

이걸 인덱서라고 하는데, 인스턴스 내의 데이터에 접근하는 방법이라고 한다.

핵심은 클래스 같은 요소도 배열처럼 사용할 수 있게 해주는 것에 있다.

 

113. Delegate의 기본, 배열에서 홀수와 짝수 찾기

using System;

namespace P113
{
    class Program
    {
        delegate bool MemberTest(int a);

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

            Console.WriteLine("Odd");
            Console.WriteLine(Count(arr, IsOdd));
            Console.WriteLine("Even");
            Console.WriteLine(Count(arr, IsEven));
        }

        static int Count(int[] a, MemberTest testMethod)
        {
            int cnt = 0;
            foreach (var n in a)
            {
                if ( testMethod(n)) cnt++;
            }
            return cnt;
        }

        public static bool IsOdd(int n) { return n % 2 != 0; }
        public static bool IsEven(int n) { return n % 2 == 0; }
    }
}

 

결과

Odd
3
Even
10

 

내가 C#을 공부하게 만든 원인 3이다.

함수2개를 한번에 사용할 수 있게 해주는 클래스이다.

 

대충 정리하면

static int Count(int[] a, MemberTest testMethod)에서 testMethod에

public static bool IsOdd(int n) { return n % 2 != 0; }
public static bool IsEven(int n) { return n % 2 == 0; }

이 2개의 메소드를 심어서 사용하는 형태가 된다.

 

114. 이름 없는 델리게이트

using System;

namespace P114
{
    class Program
    {
        delegate bool MemberTest(int a);

        static void Main(string[] args)
        {
            var arr = new[] { 3, 5, 4, 2, 6, 4, 6, 8, 54, 23, 4, 6, 4 };

            Console.WriteLine("Odd");
            int n = Count(arr, delegate (int x) { return x % 2 == 0; });
            Console.WriteLine(n);
            Console.WriteLine("Even");
            n = Count(arr, delegate (int x) { return x % 2 != 0; });
            Console.WriteLine(n);
        }

        static int Count(int[] a, MemberTest testMethod)
        {
            int cnt = 0;
            foreach (var n in a)
            {
                if (testMethod(n)) cnt++;
            }
            return cnt;
        }
    }
}

 

결과

Odd
3
Even
10

 

113에서는 delegate에서 메소드를 작성해서 넣었지만, 현재 코드처럼 람다식처럼 직접적으로 메소드 내에서 필요한 메소드를 정의해서 사용할 수 있음을 보여준다.

 

115. Func와 Action으로 델리게이트를 더 간단히 만들기

using System;

namespace P115
{
    class Program
    {
        static void Main(string[] args)
        {
            var arr = new[] { 3, 5, 4, 2, 6, 4, 6, 8, 54, 23, 4, 6, 4 };


            Console.WriteLine("Odd");
            int n = Count(arr, delegate (int x) { return x % 2 == 0; });
            Console.WriteLine(n);
            Console.WriteLine("Even");
            n = Count(arr, delegate (int x) { return x % 2 != 0; });
            Console.WriteLine(n);
        }
        static int Count(int[] a, Func<int, bool> testMethod)
        {
            int cnt = 0;
            foreach (var n in a)
            {
                if (testMethod(n)) cnt++;
            }
            return cnt;
        }
    }
}

 

결과는 113 114와 같기에 생략

 

delegate 객체 조차 귀찮은 경우를 위한 Func<>이다.

Func<int, bool>이 부분이 delagate를 대체하게 된다.

 

116. 람다식

using System;

namespace P116
{
    class Program
    {
        static void Main(string[] args)
        {
            var arr = new[] { 3, 5, 4, 2, 6, 4, 6, 8, 54, 23, 4, 6, 4 };


            Console.WriteLine("Odd");
            int n = Count(arr, x => x % 2 == 0);
            Console.WriteLine(n);
            Console.WriteLine("Even");
            n = Count(arr, x => x % 2 != 0);
            Console.WriteLine(n);
        }
        static int Count(int[] a, Func<int, bool> testMethod)
        {
            int cnt = 0;
            foreach (var n in a)
            {
                if (testMethod(n)) cnt++;
            }
            return cnt;
        }
    }
}

 

결과는 같이에 생략

delegate (int x) { return x % 2 != 0; }를 람다식으로 사용하여

x => x % 2 != 0 과 같은 형태로 생략하는 예시를 보여준다.

 

117. 람다식의 사용

1. 식람다

연산자의 오른쪽에 식이 있는 형태

A a = () => Code...

 

2. 문람다

중괄호 안에 문장을 지정함

A a = name => {};...

 

using System;

namespace P117
{
    class Program
    {
        delegate double CalcMethod(double a, double b);
        delegate bool IsTeenAger(Student student);
        delegate bool IsAdult(Student student);

        static void Main(string[] args)
        {
            Func<int, int> square = x => x * x;
            Console.WriteLine(square(5));

            int[] numbers = { 2, 3, 4, 5 };
            var squaredNumbers = numbers.Select(x => x * x);
            Console.WriteLine(string.Join(" ", squaredNumbers));

            Action line = () => Console.WriteLine();
            line();

            CalcMethod add = (a, b) => a + b;
            CalcMethod subtract = (a, b) => a - b;

            Console.WriteLine(add(10, 20));
            Console.WriteLine(subtract(10.5, 20));

            IsTeenAger isTeen = delegate (Student s) { return s.Age > 12 && s.Age < 20; };

            Student s1 = new Student() { Name = "A", Age = 18 };
            Console.WriteLine(isTeen(s1) ? "청소년" : "청소년 아님");
        }
        public class Student
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }
    }
}

 

결과

25
4 9 16 25

30
-9.5
청소년

 

적극적으로 람다식을 코드에 사용한 예시를 보여준다.

 

118. Predicate<T> 델리게이트

using System;

namespace P118
{
    class Program 
    {
        static void Main(string[] args)
        {
            Predicate<int> isEven = n => n % 2 == 0;
            Console.WriteLine(isEven(6));

            Predicate<string> Lower = s => s.Equals(s.ToLower());
            Console.WriteLine(Lower("Test"));
        }
    }
}

 

결과

True
False

 

메소드를 넣어서 쉽게 사용할 수 있게 해주는 Predicate<>델리게이트이다.

<> 변수명 = () 이 부분에 메소드를 넣으면 되는데, 보통 람다식으로 작성하여 간결화 하는 것 같다.

 

119. List<T>에서 Predicate<T>델리게이트 사용

using System;

namespace P119
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> myList = new List<string>() { "mouse", "cow", "tiger", "rabbit", "dragon", "snake" };

            bool n = myList.Exists(s => s.Contains("x"));
            Console.WriteLine(n);

            string name = myList.Find(s => s.Length == 3);
            Console.WriteLine(name);


            List<string>nameL = myList.FindAll(s => s.Length >= 3);
            foreach(var v in nameL)
                Console.WriteLine(v + " ");
        }
    }
}

 

결과

False
cow
mouse
cow
tiger
rabbit
dragon
snake

 

List<>로 생성한 객체에 predicate를 사용해보는 예시 코드이다.

람다식으로 주로 사용하며, List에 조건을 쉽게 줄 수 있는 것이 장점 같다.

 

120. LINQ의 기초

using System;
using System.Collections.Generic;
using System.Linq;

namespace P120
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> data = new List<int>() { 123, 45, 12, 89, 456, 1, 4, 74, 46 };
            List<int> lsSortedEven = new List<int>();

            foreach (var i in data) if(i % 2 == 0) lsSortedEven.Add(i);

            lsSortedEven.Sort();

            foreach (var i in lsSortedEven)
            {
                Console.Write(i + " ");
            }
            Console.WriteLine();
            var sortedEven = from i in data
                             where i % 2 == 0
                             orderby i
                             select i;

            foreach (var i in sortedEven)
            {
                Console.Write(i + " ");
            }
            Console.WriteLine();
        }
    }
}

결과

4 12 46 74 456
4 12 46 74 456

 

foreach (var i in data) if(i % 2 == 0) lsSortedEven.Add(i);

이 형태를

 

 var sortedEven = from i in data
                  where i % 2 == 0
                  orderby i
                  select i;

이렇게 사용할 수 있음을 알려준다

 

이때 where는 조건, orderby는 정렬 기준을 말하며, select는 반환값을 의미한다

즉, 일반 List를 foreach로 하면 Sort()를 추가로 해야하지만, LINQ를 사용하면 값 찾기, 정렬을 동시에 할 수 있다.

 

121. LINQ를 이용한 조건 검색과 정렬

using System;
using System.Collections.Generic;
using System.Linq;

namespace P121
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> data = new List<int>() { 123, 45, 12, 89, 456, 1, 4, 74, 46 };

            Print(data);

            var IstEven = from v in data where (v > 20 && v % 2 == 0) orderby v descending select v;

            Print(IstEven);

            var IstSorted = from v in data orderby v ascending select v;
            Print(IstSorted);
        }
        private static void Print(IEnumerable<int> data)
        {
            foreach (int item in data)
            {
                Console.Write($"[{item}] ");
            }
            Console.WriteLine();
        }
    }
}

 

결과

[123] [45] [12] [89] [456] [1] [4] [74] [46]
[456] [74] [46]
[1] [4] [12] [45] [46] [74] [89] [123] [456]

 

LINQ를 사용하여 List<>의 값들을 정리하는 예제를 보여주는 코드이다.
var IstSorted = from v in data orderby v ascending select v;

where없이 정렬만 사용하기도 하는데, 굳이 사용해야 되나 싶다...

핵심은 LINQ값을 반환하면 IEnumeable로 반환된다는 것이다. List가 아니다!

 

122. LINQ의 결과를 리스트나 배열로 반환

using System;
using System.Collections.Generic;
using System.Linq;

namespace P122
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> data = new List<int>() { 123, 45, 12, 89, 456, 1, 4, 74, 46 };
            Print(data);

            List<int> Odd = new List<int>();
            Odd = SelectOddSort(data);
            Print(Odd);

            Int32[] arrOdd;
            arrOdd = SelectOddSort(data).ToArray();
            Print(arrOdd);
        }
        private static List<int> SelectOddSort(List<int> arr)
        {
            return (from v in arr where v % 2 == 1 orderby v select v).ToList<int>();
        }
        private static void Print(IEnumerable<int> data)
        {
            foreach (int item in data)
            {
                Console.Write($"[{item}] ");
            }
            Console.WriteLine("\n");
        }
    }
}

 

결과

[123] [45] [12] [89] [456] [1] [4] [74] [46]

[1] [45] [89] [123]

[1] [45] [89] [123]

 

LINQ의 반환을 List<>로 사용해 보는 코드

원래 .ToArray();이게 책에는 없이도 작동이 되는데, 난 안된다...

 

123. 쿼리의 결과를 새로운 객체 컬렉션으로 저장하는 방법

using System;
using System.Collections.Generic;
using System.Linq;

namespace P123
{
    class Student
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public List<int> Scores { get; set; }
    }
    class Program
    {
        static List<Student> students;
        static void Main(string[] args)
        {
            students = new List<Student>()
            {
                new Student { Name = "A", Id = 1 , Scores = new List<int>() { 1, 50 } },
                new Student { Name = "B", Id = 2 , Scores = new List<int>() {3, 60} },
                new Student { Name = "C", Id = 3 , Scores = new List<int>() {5, 70} }
            };
            Print(students);

            High(0, 3);
            High(1, 60);
        }
        private static void High(int n ,int cut)
        {
            var high = from Student in students where Student.Scores[n] >= cut select new { Name = Student.Name, Scores = Student.Scores[n] };
            foreach (var v in high)
            {
                Console.Write($"[{v.Name}] : {v.Scores}");
            }
            Console.WriteLine();
        }

        private static void Print(List<Student> value)
        {
            foreach (var v in value)
            {
                Console.Write($"[{v.Name}] [{v.Id}] [{v.Scores[0]} {v.Scores[1]}]  " );
            }
            Console.WriteLine("\n");
        }
    }
}

 

결과

[A] [1] [1 50]  [B] [2] [3 60]  [C] [3] [5 70]

[B] : 3[C] : 5
[B] : 60[C] : 70

 

LINQ로 만든 결과를 new 객체에 담아서 즉시 출력해보는 코드이다.

이때 Students를 static으로 만들어, 메소드가 매개변수 없이 작동할 수 있게 설계되어 있다.

 

124. Linq, Group By로 데이터를 분류

using System;
using System.Collections.Generic;
using System.Linq;

namespace P124
{
    class Student
    {
        public string Name { get; set; }
        public int Id { get; set; }
        public List<int> Scores { get; set; }
    }
    class Program
    {
        static List<Student> students;
        static void Main(string[] args)
        {
            students = new List<Student>()
            {
                new Student { Name = "A", Id = 1 , Scores = new List<int>() { 80, 80 } },
                new Student { Name = "B", Id = 2 , Scores = new List<int>() {90, 80} },
                new Student { Name = "C", Id = 3 , Scores = new List<int>() {5, 80} },
                new Student { Name = "D", Id = 4 , Scores = new List<int>() {5, 90} }
            };

            var result = from v in students
                         group v by v.Scores.Average() >= 80 into g
                         select new
                         {
                             key = g.Key? "over 80" : "low 80",
                             count  = g.Count(),
                             avr = g.Average(v => v.Scores.Average()),
                             max = g.Max(v => v.Scores.Max())
                         };
            foreach ( var v in result )
            {
                Console.WriteLine( $"{v.key} 학생수 {v.count}" );
                Console.WriteLine($"{v.key} 평균 {v.avr:F2}");
                Console.WriteLine($"{v.key} 최고 {v.max:F2}");
                Console.WriteLine();
            }
        }
    }
}

 

결과

over 80 학생수 2
over 80 평균 82.50
over 80 최고 90.00

low 80 학생수 2
low 80 평균 45.00
low 80 최고 90.00

 

Linq의 결과를 result에 넣어서 2개의 key로 분류하여 출력하는 코드이다.

이때 group by를 사용하게 된다.

 

GitHub - NoNamed02/C-sharp-Studying: C#언어 공부 정리

C#언어 공부 정리. Contribute to NoNamed02/C-sharp-Studying development by creating an account on GitHub.

github.com