해당 문제는 트로피가 에제 입력 1처럼 1자로 쭉 나열되어 있을 때, 각각의 값들이 트로피의 높이라고 할 수 있다.
트로피의 높이를 왼쪽에서 보았을 때, 오른쪽에서 보았을 때 높이가 다르기 때문에 높이가 작은 트로피 큰 트로피에 가려져서 안보인다고 한다. 그래서, 왼쪽에서 보았을 때와 오른쪽에서 보았을 때 각각 보이는 개수를 출력하는 문제이다.
이 문제는 트로피의 개수 N이 최대 50이라고 했으므로, 요구하는 대로 문제를 풀어보면 된다.
우선 3 , 4, 6, 4, 3, 7, 2 트로피가 있다고 가정 해보면 왼족에서 보았을 때, 6뒤에 4 3이 가려져서 안보이고 7뒤에 2가 가려져서 안보이기에 왼쪽에는 4,3,2를 제외한 총 4개가 보이는 것이다.
오른쪽에서 보았을 때는 7이 너무 커서 뒤에 있는 3, 4, 6, 4, 3은 전부 안보이기에 총 2개가 보이는 것이다.
def ascending(array):
now = array[0]
result = 1
for i in range(1, len(array)):
if now < array[i]:
result += 1
now = array[i]
return result
n = int(input())
array = []
for _ in range(n):
array.append(int(input()))
print(ascending(array))
array.reverse()
print(ascending(array))
ascending()이란 하나의 함수를 만들었는데, 왼쪽에서 보았 을 때 트로피 갯수를 세는 함수라고 볼 수 있다.
오름차순으로 원소들만 센다.
예를 들어, 3,5,7,2,9 라는 숫자가 있으면 3,5,7 센 다음 2는 오름차순이 아니기에 건너뛰고 9를 센다.
now가 현재 보고 있는 트로피의 높이라고 할 수 있고,
결과적으로 result를 현재 보고 있는 트로피가 더 높은 트로피라면 +=1을 하는 방식으로 구현 한다.
이 함수를 이용해서
print(ascending(array))를 통해, 왼쪽에서 보고 있는 걸 출력해두고,
array.reverse()를 통해 반대로 뒤집어서 오른쪽에서 보고 있는걸 출력 할 수 있다.
내용을 보면,가장 많이 팔린 책을 출력하면 되는 간단한 문제이다. 예를 들어 예제 입력1에서 top이 4번 나왔고,kimtop이 허1번 나왔으면, top이 가장 많이 나왔으니 top을 출력하면 되는 것이다.
이 문제는 가장 많이 등장한 문자열을 출력하는 문제이므로, 어떠한 원소를 나왔는지 안나왔는지를 구분하기 위해
set() 자료형이나 Dictionary()자료형을 이용할 수 있다. 이 문제 같은 경우, 나온 횟수를 세어야 하기 때문에 Dictionary() 자료형을 이용한다. 횟수를 계산할 때는 Dictionary()를 이용하면 효과적이다.
n = int(input())
books = {}
for _ in range(n):
book = input()
if book not in books:
books[book] = 1
else:
books[book] += 1
target = max(books.values())
array = []
for book, number in books.items():
if number == target:
array.append(book)
print(sorted(array)[0])
책이 등장한 횟수를 세기 위해서 books = {} 라고 하나의 dictionary자료형을 만들었다.
그 다음 데이터를 입력 받을 때 마다. 해당 책이 dictionary에 들어있지 않다면 1로 설정한다. 이유는 하나의 책이 새로 들어온 것이니까. 그다음, 해당 책이 한번이라도 등장한 경험이 있다면 등장횟수에 1을 더해주는 것이다.
for _ in range(n): book = input() if book not in books: books[book] = 1 else: books[book] += 1
이 코드를 수행하게 되면 책이 등장한 횟수만큼 1을 더해주게 된다.
그 다음, 해당 books를 값을 기준으로 정렬을 해서, 가장 큰 값을 가져오는 것이다. max를 가장 큰 함수를 가져오는 함수니까 target에 넣는다. 이 코드를 예를 들자면, 예제출력 1에서 보았던 top에서 4번 등장한 횟수가 가장 많았던 것처럼 top이 출력되는 것이다.
for book, number in books.items(): if number == target: array.append(book)
여기서 등장횟수가 가장 큰 것과 동일 하다면 array에다가 담고, 사전 순으로 가장 책의 이름이 앞 쪽에 있는 것을 출력하게 만들도록, sorted 로 print했다.
새들은 1부터 오름차순으로 반복적으로 증가하므로, 날아가는 새의 마리 수는 빠르게 증가한다는 것을 알 수 있다.
그럼 등차수열이기에 O(n²)으로 시간복잡도가 분류된다. 그렇기에 N이 큼에도 불구하고 단순하게 요구하는대로 풀 수 있다.예시입력이 14인 것을 보면, 1 2 3 4 에서 5마리의 새는 날아가지 못하니까(15가 됨) 다시 1부터 시작해서 1 2 에서 13이 되고 3마리의 새는 날아가지 못하고 다시 1이 되니까 1 2 3 4 1 2 1 이니까 총 7초가 걸린다.
n = int(input())
result = 0
k = 1
while n != 0: # 모든 새가 날아갈 때까지
if k > n:
k = 1
n -= k
k += 1
result += 1
print(result)
여기서 k는 1부터 출발을 하고, 입력된 숫자 'n'의 값이 0이 될 때까지, 즉 모든 새가 다 날아갈 때까지 반복한다. 순차적으로 증가하는 수 'k'를 이용해서 'n'에서 계속 빼는데, k가 n보다 커질 시, k는 다시 1로 재설정되면서 반복된다.
각 루프가 완료될 때마다 result 변수는 1씩 증가해서 총 몇 초가 걸리는지 확인할 수 있다.
예제 입력1 같은 경우 aba aba가 두번 찾을 수 있기에 예제출력에서 2와 같은 것이 나오고,
예제 입력2 같은 경우 aa가 두번 있기에 2번
예제 입력3 같은 경우 ababa가 한번 있기에 1
예제 입력4 같은 경우 aa가 매치가 안되는 것 없이 전부 매치되기에 3이 출력된다.
문서의 길이는 최대 2,500이고 단어의 길이는 최대 50이다.
그러면 단순하게 모든 경우의 수를 계산하여 문제를 해결 가능 하다. 그럼 시간복잡도 O(NM)의 알고리즘으로 해결 가능하다. 모든 경우를 탐색해도 약 10만정도의 작은 수 이기 때문이다.
document = input()
word = input()
index = 0
result = 0
while len(document) - index >= len(word):
if document[index:index + len(word)] == word: # 문서에서 보고 있는 단어가 찾고자 하는 단어인 경우
result += 1
index += len(word)
else:
index += 1
print(result)
index = 0을 만들어 줌으로 써 index 0부터 차례대로 비교할 수 있도록 설계를 시작한다.
이후 while문을 통해서 단어가 벗어나지 않을 때 까지 반복을 해주면서, 비교를 할 때 마다 문서에서 index부터 단어의 길이만큼 확인을 해서 == word로 단어와 정확히 일치하는지,만약 찾고자 하는 단어와 일치하는 경우 단어의 길이만큼 ( index += len(word) )를 통해서 index를 더해준다. 찾지 못한 경우,
그러나 첫째 줄에 수의 개수가 최대 백만 개 까지 주어질 수 있으며, 2초 이내에 정렬해야 되는 문제이다.
그렇기 때문에 효과적인 알고리즘을 이용해야 한다. 여기서는 시간 복잡도 O(NlogN)의 정렬 알고리즘을 이용 해보았다. 그럼 약 2천만번의 연산 횟수가 만들어 진다.(파이썬으로 할 시, 1초에 2천만번 정도의 연산이 가능하다.)
알고리즘은 병합 정렬,퀵 정렬, 힙 정렬을 사용 할 수 있지만 퀵 정렬에서는 O(n²)이 나올 수 있기에, 병합,힙을 이용하거나, 파이썬의 기본 정렬 라이브러리를 이용할 수 있다.
병합 정렬은 시간복잡도 O(NlogN)을 보장하기에 병합 정렬을 이용하고, 메모리 제한이 없는 문제이기에 PyPy3를 이용했다.
def merge_sort(array):
if len(array) <= 1:
return array
mid = len(array) // 2
left = merge_sort(array[:mid])
right = merge_sort(array[mid:])
i, j, k = 0, 0, 0
while i < len(left) and j < len(right):
if left[i] < right[j]:
array[k] = left[i]
i += 1
else:
array[k] = right[j]
j += 1
k += 1
if i == len(left):
while j < len(right):
array[k] = right[j]
j += 1
k += 1
elif j == len(right):
while i < len(left):
array[k] = left[i]
i += 1
k += 1
return array
n = int(input())
array = []
for _ in range(n):
array.append(int(input()))
array = merge_sort(array)
for data in array:
print(data)
return array까지 기존 병합정렬 코드에서 array만 넣어주면, 자동으로 해당 리스트를 정렬 해준다는 특징이 있기에 병합정렬을 이용하기 위해 n = int(input())로 데이터의 개수를 받고,
for _ in range(n): array.append(int(input())) 으로 차례대로 데이터의 개수 만큼 리스트에 원소를 채워 넣는 다음,
array = merge_sort(array)로 정렬을 한 뒤에
정렬한 데이터를
for data in array: print(data)로 한 줄에 하나씩 출력하도록 만들었다.
아니면 Python 기본적으로 제공해주는 내장함수 sorted를 이용해서 더 쉽게 문제 해결도 가능하다.
n = int(input())
array = []
for _ in range(n):
array.append(int(input()))
array = sorted(array)
for data in array:
print(data)
1. 대한민국에 거주하는 고객의 고객명,주소,연락처를 보이는 프로시저를 작성하고 동작됨을 보이시오.
--프로시저 생성
CREATE OR REPLACE PROCEDURE GET_KR_USER_PRC(rc OUT SYS_REFCURSOR)
AS
BEGIN
OPEN rc FOR
SELECT NAME,
ADDRESS,
PHONE
FROM CUSTOMER c WHERE ADDRESS LIKE '%대한민국%';
END GET_KR_USER_PRC;
--동작 확인
DECLARE
rc SYS_REFCURSOR;
NAME CUSTOMER.NAME%TYPE;
ADDRESS CUSTOMER.ADDRESS%TYPE;
PHONE CUSTOMER.PHONE%TYPE;
BEGIN
GET_KR_USER_PRC(rc);
LOOP
FETCH rc INTO NAME, ADDRESS, PHONE;
EXIT
WHEN rc%notfound;
dbms_output.put_line(NAME || ',' || ADDRESS || ',' || PHONE);
END LOOP;
END;
2. 도서 테이블에 동일도서(출판사,책이름이 동일)가 있으면 도서의 가격만 새롭게 변경하고 그렇지 않으면 새로운 행을 삽입하는 프로시저를 작성하고 동작됨을 보이시오.
--프로시저 생성
CREATE OR REPLACE PROCEDURE BOOK_PRICE_PRC(in_publisher IN BOOK.PUBLISHER%TYPE,
in_bookname IN BOOK.BOOKNAME%TYPE,
in_price BOOK.PRICE%TYPE)
AS d_book_id BOOK.BOOKID%TYPE;
d_max_book_id BOOK.BOOKID%TYPE;
BEGIN
BEGIN
SELECT bookid INTO d_book_id
FROM BOOK b
WHERE b.BOOKNAME = in_bookname
AND b.PUBLISHER = in_publisher;
EXCEPTION
WHEN NO_DATA_FOUND THEN
d_book_id := 0;
END;
BEGIN
SELECT MAX(bookid)+1 INTO d_max_book_id
FROM BOOK b;
EXCEPTION
WHEN NO_DATA_FOUND THEN
d_max_book_id := 1;
END;
IF(d_book_id = 0)THEN
INSERT INTO BOOK (BOOKID, BOOKNAME, PUBLISHER, PRICE)
VALUES(d_max_book_id, in_bookname, in_publisher, in_price);
ELSE
UPDATE BOOK
SET PRICE=in_price
WHERE BOOKID=d_book_id;
END IF;
END BOOK_PRICE_PRC;
--동작 확인
SELECT * FROM BOOK;
call BOOK_PRICE_PRC('test3','test2',4000);
call BOOK_PRICE_PRC('대한미디어','축구의 이해',1000);
SELECT * FROM BOOK;
3. 특정 고객의 주문 총액을 계산하여 3만원 이상이면 ‘우수’, 3만원 미만이면 ‘일반’을 반환하는 함수 grade()를 작성하고 동작됨을 보이시오.
CREATE OR REPLACE FUNCTION grade(v_custid NUMBER)
RETURN VARCHAR
IS
v_grade varchar(100);
BEGIN
SELECT CASE WHEN SUM(o.SALEPRICE) >= 30000
THEN '우수'
ELSE '일반'
END INTO v_grade
FROM ORDERS o
WHERE o.CUSTID=v_custid;
RETURN v_grade;
END;
SELECT grade(2) AS grade
FROM dual;
4. 3번문에에서 작성한 사용자정의 함수 grade()를 호출하여 고객의 이름과 등급을 보이는 SQL문을 작성하고 실행결과를 보이시오.
SELECT c.NAME,
grade(c.CUSTID) AS grade
FROM CUSTOMER c;
5. 고객별로 도서를 몇 권 구입 했는지와 총구매액을 보이는 프로시저를 작성하고 동작됨을 보이시오.
--프로시저 생성
CREATE OR REPLACE PROCEDURE GET_BOOK_ORDER_BYCUST_PRC(rc OUT SYS_REFCURSOR)
AS
BEGIN
OPEN rc FOR
SELECT o.CUSTID,
COUNT(1) AS BOOK_COUNT,
SUM(o.SALEPRICE) AS SALEPRICE
FROM ORDERS o
GROUP BY o.CUSTID ;
END GET_BOOK_ORDER_BYCUST_PRC;
--동작 확인
DECLARE
rc SYS_REFCURSOR;
BOOK_COUNT number;
CUSTID number;
SALEPRICE number;
BEGIN
GET_BOOK_ORDER_BYCUST_PRC(rc);
LOOP
FETCH rc INTO CUSTID, BOOK_COUNT, SALEPRICE;
EXIT
WHEN rc%notfound;
dbms_output.put_line(CUSTID || ',' || BOOK_COUNT || ',' || SALEPRICE);
END LOOP;
END;
6. 고객이 주문한 내용의 변경이 발생할 경우 로그테이블에 변경전 변경후 데이터를 기록하는 트리거를 작성하고 동작됨을 보이시오.
CREATE TABLE ORDERS_LOG
(
"NO" NUMBER(10,0) PRIMARY KEY,
"ORDERID" NUMBER(2,0),
"BEFORE_CUSTID" NUMBER(2,0),
"AFTER_CUSTID" NUMBER(2,0),
"BEFORE_BOOKID" NUMBER(2,0),
"AFTER_BOOKID" NUMBER(2,0),
"BEFORE_SALEPRICE" NUMBER(8,0),
"AFTER_SALEPRICE" NUMBER(8,0),
"BEFORE_ORDERDATE" DATE,
"AFTER_ORDERDATE" DATE,
"UPDATE" DATE
) ;
--시퀀스 생성
CREATE SEQUENCE ORDERS_LOG_NO_SEQ INCREMENT BY 1 MINVALUE 0 NOCYCLE NOCACHE NOORDER;
--트리거 생성
CREATE OR REPLACE TRIGGER c##sql3.ORDERS_UPDATE
AFTER UPDATE
ON ORDERS
FOR EACH ROW
BEGIN
INSERT INTO ORDERS_LOG
(
"NO",
ORDERID,
BEFORE_CUSTID,
AFTER_CUSTID,
BEFORE_BOOKID,
AFTER_BOOKID,
BEFORE_SALEPRICE,
AFTER_SALEPRICE,
BEFORE_ORDERDATE,
AFTER_ORDERDATE,
"UPDATE")
VALUES(
ORDERS_LOG_NO_SEQ.nextval,
:OLD.ORDERID,
:OLD.CUSTID,
:NEW.CUSTID,
:OLD.BOOKID,
:NEW.BOOKID,
:OLD.SALEPRICE,
:NEW.SALEPRICE,
:OLD.ORDERDATE,
:NEW.ORDERDATE,
SYSDATE);
END;
UPDATE ORDERS
SET CUSTID=5, BOOKID=6, SALEPRICE=13000, ORDERDATE=TIMESTAMP '2022-07-03 00:00:00.000000'
WHERE ORDERID=11;
SELECT * FROM ORDERS_LOG;
SELECT b.PUBLISHER, o.CUSTID, SUM(o.SALEPRICE) AS PRICE
FROM ORDERS o
LEFT JOIN BOOK b ON o.BOOKID = b.BOOKID
GROUP BY ROLLUP(b.PUBLISHER, o.CUSTID) ;
8. 윈도우 함수를 이용하여 출판사별 총판매금액, 판매순위를 산출하는 DML문 작성하고 실행해 보이시오.
SELECT b.PUBLISHER, SUM(o.SALEPRICE) AS PRICE,
RANK() OVER (ORDER BY SUM(o.SALEPRICE) DESC) AS RANKING
FROM ORDERS o
LEFT JOIN BOOK b ON o.BOOKID = b.BOOKID
GROUP BY b.PUBLISHER ;
public class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
// Default constructor
public Rectangle()
{
Width = 0;
Height = 0;
}
// Constructor overloading
public Rectangle(int side)
{
Width = Height = side;
}
public Rectangle(int width, int height)
{
Width = width;
Height = height;
}
}
이 것을 다른 .cs에 있다고 가정 했을 때,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp2
{
class Program
{
static void Main()
{
Rectangle r1 = new Rectangle();
Console.WriteLine($"Width: {r1.Width}, Height: {r1.Height}");
Rectangle r2 = new Rectangle(5);
Console.WriteLine($"Width: {r2.Width}, Height: {r2.Height}");
Rectangle r3 = new Rectangle(4, 7);
Console.WriteLine($"Width: {r3.Width}, Height: {r3.Height}");
}
}
}
.Height,.Width로 가져올 수 있다.
<상속과 Protected>
C#에서 상속을 사용하면 한 클래스가 다른 클래스의 속성과 메소드를 상속 받을 수 있다. protected 접근 한정자는 해당 클래스 및 상속받은 클래스에서만 접근이 가능하게 한다.
상속: 다른 클래스에 정의된 멤버를 불려 받을 수 있는 기능 상속해주는 클래스 - 부모클래스 상속 받는 클래스 - 자식클래스
public class Animal
{
protected int legs = 4; // protected 변수
public void Eat()
{
Console.WriteLine("Eating...");
}
}
public class Dog : Animal // Animal 클래스를 상속 받음
{
public void Bark()
{
Console.WriteLine($"Barking with {legs} legs..."); // protected 변수 사용
}
}
class Program
{
static void Main()
{
Dog dog = new Dog();
dog.Eat();
dog.Bark();
}
}
< Sealed 클래스와 메소드 오버라이딩 >
C#에서 'sealed' 키워드는 클래스를 봉인하여 다른 클래스가 해당 클래스를 상속받는 것을 막는다.
즉, 클래스명 앞에 sealed를 붙이면 상속을 못 하고 인스턴스화를 해서만 사용할 수 있다.
오버라이딩 (Overriding) : 오버로딩과 비슷하지만 오버로딩은 클래스내에서 동일한 이름으로 매개변수를 다르게 하는 방식이고 오버라이딩은 클래스의 상속관계에서 메소드를 재정의 하는 방법
sealed class SealedClass
{
public int x;
public int y;
}
class Program
{
static void Main()
{
SealedClass sc = new SealedClass();
sc.x = 10;
sc.y = 20;
Console.WriteLine($"x = {sc.x}, y = {sc.y}");
}
}
메소드 오버라이딩
C#에서 메소드 오버라이딩은 상속받은 메소드를 자식 클래스에서 재정의하는 것을 의미한다. 이를 위해서는 기본 클래스의 메소드에 virtual 키워드를 사용하고, 파생 클래스에서는 override 키워드를 사용해야 한다.
public class Animal
{
public virtual void sound()
{
Console.WriteLine("This is the sound of an animal");
}
}
public class Dog : Animal
{
public override void sound()
{
Console.WriteLine("This is the sound of a dog");
}
}
class Program
{
static void Main()
{
Animal myAnimal = new Animal();
Animal myDog = new Dog();
myAnimal.sound();
myDog.sound();
}
}
< Partial 클래스>
파샬 partial class : 두개 이상의 파일이 클래스를 나뉘어서 개밝하는 방식 컴파일시 자동으로 결합이 되고, 코드가 길어질 경우 관리를 수월하게 할 수가 있고, 하나의 클래스를 여러명에서 동시에 작성할 수 있다. partial class 클래스명 { //코드 }
// File1.cs
public partial class PartialClass
{
public void Method1()
{
Console.WriteLine("Method 1");
}
}
// File2.cs
public partial class PartialClass
{
public void Method2()
{
Console.WriteLine("Method 2");
}
}
class Program
{
static void Main()
{
PartialClass myClass = new PartialClass();
myClass.Method1();
myClass.Method2();
}
}
< 추상 클래스>
C#에서 추상 클래스(abstract class)는 인스턴스를 만들 수 없고, 하나 이상의 추상 메서드(정의되지 않은 메서드, 즉 프로토타입만 있는 메서드)를 가질 수 있는 클래스를 말한다. 이 클래스는 반드시 상속을 통해 사용되며, 상속받은 클래스에서 추상 메서드를 구현(override)해야 한다.
abstract 추상클래스:
상속을 해주기 위한 클래스
abstract class 추상클래스
{
abstract public void message(); //상속받은 클래스에서 기능 구현
}
class 자식클래스 : 추상클래스
{
public override void message()
{
Console.WriteLine(“코드구현”);
}
}
예를 들어서 동물소리를 추상메서드로 사용한다고 가정해보자.
public abstract class Animal
{
public abstract void animalSound(); // 추상 메서드
public void sleep()
{
Console.WriteLine("Zzz");
}
}
이젠 돼지가 Animal을 오버라이드하여 구현하면 된다.
public class Pig : Animal
{
public override void animalSound() // 추상 메서드를 오버라이드하여 구현
{
Console.WriteLine("The pig says: wee wee");
}
}
class Program
{
static void Main()
{
Pig myPig = new Pig();
myPig.animalSound();
myPig.sleep();
}
}
< 정적 Static 클래스>
static 정적 클래스 : 인스턴스를 만들어서 사용할 수 없다. 생성자를 포함할 수 없다. 어디서든 접근할 수 있다.
static class 클래스명
{
static public string name;
}
public static class MyMathClass
{
public static int Square(int num)
{
return num * num;
}
}
static void Main()
{
int result = MyMathClass.Square(5); // 인스턴스 생성 없이 사용
Console.WriteLine(result);
}
< 인터페이스와 네임스페이스>
interface 인터페이스: 메소드 선언은 있지만, 기능을 구현하는 코드는 없다. 다중 상속을 위해 존재한다.
public interface 인터페이스명
{
void interfaceVoid();
}
public class 클래스명 : 인터페이스명
{
public void interfaceVoid()
{
//코드
}
}
네임스페이스 namespace : 유효범위를 제공하는 선언,모든 식별자가 고유하도록 보장한다.
namespace ShapeNamespace
{
public interface IShape
{
double GetArea();
}
public class Rectangle : IShape
{
public double Length { get; set; }
public double Width { get; set; }
public double GetArea()
{
return Length * Width;
}
}
}
파일을 별도로 분리하고 싶으면, Rectangle을 다른 파일에다가 옮겨도 똑같은 값이 나온다.
class Program
{
static void Main()
{
Rectangle rectangle = new Rectangle();
rectangle.Length = 5.0;
rectangle.Width = 3.0;
Console.WriteLine(rectangle.GetArea());
}
}
< 대리자와 익명 메소드>
대리자 delegate: 매개변수와 반환형식을 갖는 메소드를 캡슐화 하며, 대리자는 참조하는 메소드의 메모리 주소를 가진다. 메소드를 보관하는 공간이고 필요할 때 이 공간을 가져와서 함수를 실행한다.
public delegate void MyDelegate(string msg);
class Program
{
public static void Hello(string strMessage)
{
Console.WriteLine("Hello, " + strMessage);
}
public static void Goodbye(string strMessage)
{
Console.WriteLine("Goodbye, " + strMessage);
}
static void Main()
{
MyDelegate del = Hello;
del("Alice");
del = Goodbye;
del("Bob");
}
}
익명메소드: 별도의 메소드를 만들지 않고 불필요한 오버헤드를 줄일 수가 있다. 재사용할 필요가 없을 경우 사용한다.
public delegate void MyDelegate(string msg);
class Program
{
static void Main()
{
MyDelegate del = delegate(string name)
{
Console.WriteLine($"Hello, {name}");
};
del("Charlie");
}
}
< 이벤트 핸들러>
C#에서 이벤트는 특정한 일이 일어날 때마다 호출되는 방법을 제공한다. 이벤트는 대리자를 사용하여 정의된다.
public delegate string MyDel(string str);
class EventProgram
{
event MyDel MyEvent;
public EventProgram()
{
this.MyEvent += new MyDel(this.WelcomeUser);
}
public string WelcomeUser(string username)
{
return "Welcome " + username;
}
static void Main(string[] args)
{
EventProgram obj1 = new EventProgram();
string result = obj1.MyEvent("Tutorials Point");
Console.WriteLine(result);
}
}
< 문자열 다루기>
class Program
{
static void Main()
{
string txt = "Hello World";
Console.WriteLine("Length: " + txt.Length); // 문자열 길이 확인
Console.WriteLine("Upper: " + txt.ToUpper()); // 대문자로 변환
Console.WriteLine("Lower: " + txt.ToLower()); // 소문자로 변환
Console.WriteLine("Contains: " + txt.Contains("World")); // 특정 문자열 포함 여부 확인
Console.WriteLine("Index: " + txt.IndexOf("World")); // 특정 문자열의 위치 찾기
}
}
여기서 "Hello,World!" 다음 새로운 줄에서 "Hello,C#"가 출력되는 것을 볼 수 있다.
< 콘솔에 입력받기 >
C#에서 사용자로부터 입력을 받기 위해서는 'Console.ReadLine()' 메소드를 사용한다.
Console.WriteLine("Enter your name:");
string name = Console.ReadLine();
Console.WriteLine($"Hello, {name}!");
위 코드를 실행하면 콘솔이 사용자로부터 이름을 입력받고, 입력받은 이름을 사용하여 메세지를 출력한다.
< 데이터 타입 알아보기 >
int number = 10;
double pi = 3.141592;
char character = 'A';
bool isTrue = true;
string name = "C#";
< 데이터타입 사용방법과 변수 상수 선언 >
C#에서의 변수와 상수 선언
C#에서 변수는 '변수타입 변수명 = 초기값;' 형태로 선언한다. 변수는 값이 변경될 수 있다.
상수는 'const 상수타입 상수명 = 초기값;'의 형태로 선언한다. 상수는 한번 선언되면 값을 변경할 수 없다.
string name = "홍길동";
name = "1";
name = "0.5"; //string은 숫자가 아닌 문자열 이다.
char letter = 'A'; //char는 ''로 한다. ""로 할 시, 오류
int price = 100;
// price = 0.5; //소숫점은 넣을 수 없다.
double b = 0.05;
decimal sale = Convert.ToDecimal(1.5); //decimal은 Convert.ToDecimal()로 형변환을 알려주고 넣거나
decimal sale_price;
sale_price = price - (price * sale); //선언 하고 난 뒤 결과 값을 받을 수 있다.
Console.WriteLine("할인된 가격은 {0}", sale_price);
Console.ReadLine();
const string str = "홍길동"; //const는 상수로서 변경 불가능 하다.
< Object Var Dynamic 타입과 연산자 >
C#은 Object, Var, Dynamic이라는 특별한 타입을 가지고 있다.
Object: C#의 모든 타입은 Object 타입에서 파생되므로, 어떤 타입의 데이터도 저장할 수 있다.
Var: 컴파일 타임에 타입이 결정되며, 선언 시 초기화를 해주어야 한다.
Dynamic: 런타임에 타입이 결정되며, 선언 시 초기화를 하지 않아도 된다.
이들 타입과 함께 하는 사용하는 연산자에는 사칙연산자(+,-,*,/),비교연산자(==,!=,<,>,<=,>=)등이 있다.
object aa = 11;
aa = "감자";
int a = Convert.ToInt32(aa); //object에서는 다른 형으로 재할당 시, Convert.Toint32(aa);로 해야 한다.
object aaa = "a";
Console.WriteLine("aa값은: {0}", aa);
var bb = 22;
//bb = "b"; //var type은 처음에 숫자가 들어가면, 그 다음에 문자로 바꿀 수 없다.
Console.WriteLine("bb값은: {0}", bb);
dynamic cc = 33;
cc = "감자";//형을 바꿔서 넣을 수 있다.
dynamic ccc = "c";
cc = "한글";
int c = cc;//실행되는 시점에서 검사를 하기에, 실행하는 시점에서만 오류인지 아닌지 알 수 있다.
Console.WriteLine("cc값은: {0}", cc);
Console.ReadLine();
//연산자
int a = 10;
int b = 5;
int c = a + b;
Console.WriteLine("a+b={0}", c);
Console.WriteLine("a+b={0}", a + b);
Console.WriteLine("a+b={0}", a - b);
Console.WriteLine("a*b={0}", a * b);
Console.WriteLine("a/b={0}", a / b);
Console.ReadLine();
int d;
d = 5 / 2;
Console.WriteLine("d의 값은? {0}", d);
double e;
e = 5 / 2;
Console.WriteLine("e의 값은? {0}", e);
double f;
f = 5.0 / 2;
Console.WriteLine("f의 값은? {0}", f);
float g;
g = 5f / 2f;
Console.WriteLine("g의 값은? {0}", g);
Console.ReadLine();
< 증감연산자,산술연산자 >
C#에서는 증감연산자와 산술연산자를 지원한다.
증감연산자 :
++ : 값을 1 증가 시킨다.
-- : 값을 1 감소시킨다.
산술연산자 :
+ : 더하기 연산
- : 빼기 연산
* : 곱하기 연산
/ : 나누기 연산
% : 나머지 연산
/*
연산자 종류
증감연산자 ++,--
산술연산자 +,-,*,/,%
*/
int a = 1;
int b = 2;
int c;
c = ++a;
Console.WriteLine("선행연산자 a의 값 {0} c의 값{1}", a, c); //a의 값 2 c의 값 2
a = 1;
c = a++;
Console.WriteLine("선행연산자 a의 값 {0} c의 값{1}", a, c); //a의 값 2 c의 값 1
a = 1;
c = --a;
Console.WriteLine("선행연산자 a의 값 {0} c의 값 {1}", a, c); //a의 값 0 c의 값 0
c = a--;
Console.WriteLine("선행연산자 a의 값 {0} c의 값 {1}", a, c); //a의 값 -1 c의 값 0
Console.WriteLine("나머지값 {0}", 5 % 2); //나머지 값 1
< IF문 관계연산자 논리연산자 >
C#에서는 if문,관계연산자,논리연산자를 사용하여 조건에 따라 코드를 실행할 수 있다.
if문 :
if문은 조건식이 참일 때 해당 코드 블록을 실행한다.
관계연산자:
==:같다.
!= : 다르다.
< : 작다
> : 크다.
<= : 작거나 같다.
>= : 크거나 같다.
논리 연산자 :
&& : 논리 AND 연산, 모든 조건이 참일 때, 참을 반환한다.
|| : 논리 OR 연산, 조건 중 하나 이상이 참일 때 참을 반환한다.
! : 논리 NOT 연산 , 조건의 반대를 반환한다.
/*
관계 연산자 <,>,==,!=,<=,>=
논리 연산자 &&,||,!
*/
int a = 3;
if (a == 1)
{
Console.WriteLine("1과 같음");
}
else if (a >= 1)
{
Console.WriteLine("1보다 크거나 같음");
}
else if (a < 1)
{
Console.WriteLine("1보다 작음");
}
else
{
Console.WriteLine("해당없음");
}
int b, c;
b = 100;
c = 200;
if (b == 100 && c == 300)
{
Console.WriteLine("1");
}
else if (b == 100 || c == 300)
{
Console.WriteLine("1");
}
else if (b > 100 || c == 300)
{
Console.WriteLine("3");
}
else if (b != 100 || c != 300)
{
Console.WriteLine("4");
}
< 형변환 암시적 명시적 변환 >
C#에서의 데이터 타입간 암시적 변환과 명시적 변환을 사용할 수 있다.
암시적 변환: 데이터 손실이 없는 경우, 컴파일러가 자동으로 변환을 수행한다.
명시적 변환: 데이터 손실이 있는 경우, 개발자가 명시적으로 변환을 지시해야 한다.
/*
타입 자동 변환되는 유형
byte short,ushort,int,unit,long,ulong,float,double,decimal
sbyte short,int,long,float,double,decimal
short int,long,float,double,decimal
ushort int,unit,long,ulong,float,double,decimal
int long,float,double,decimal
uint long,ulong,float,double,decimal
long float,double,decimal
ulong float,double,decimal
float double
char ushort,int,unit,long,ulong,float,double,decimal
var 암시적 변환 타입
*/
char a1 = 'a';
char a2 = 'A';
Console.WriteLine("a1의 값:" + a1);
Console.WriteLine("a2의 값:" + a2);
ushort change_a1, change_a2;
change_a1 = a1;
change_a2 = a2;
Console.WriteLine("change_a1의 값:" + change_a1);
Console.WriteLine("change_a2의 값:" + change_a2);
byte ch_byte_a1, ch_byte_a2;
ch_byte_a1 = (byte)a1;
ch_byte_a2 = Convert.ToByte(a2);
Console.WriteLine("ch_byte_a1의 값:" + ch_byte_a1);
Console.WriteLine("ch_byte_a2의 값:" + ch_byte_a2);
< 소수점 자리수 조절, 문자열 코드 >
C#에서는 소수점 자리수 조절을 위해 'Math.Round()', 문자열 조절을 위해 'string.Format()'을 사용할 수 있다.
double number = 3.141592;
number = Math.Round(number, 2); // 소수점 아래 두 자리까지 반올림, number는 3.14
string str = string.Format("{0:N2}", number); // 숫자를 문자열로 변환하며 소수점 아래 두 자리까지 표현, str은 "3.14"
< For문 배열 메소드 사용 방법 >
C#에서 'for'문을 사용하여 반복 작업을 처리하고, 배열을 사용하여 어러 값을 저장 하며, 메소드를 사용하여 작업을 재사용할 수 있다.
int[] array = new int[5] {1, 2, 3, 4, 5};
for(int i = 0; i < array.Length; i++)
{
array[i] = MultiplyByTwo(array[i]);
Console.WriteLine(array[i]);
}
int MultiplyByTwo(int number)
{
return number * 2;
}
< 전역변수 지역변수 열거형 Enum >
C#에서 전역변수는 클래스 내 어디서는 접근 가능한 변수이며, 지역변수는 특정 블록(메소드,if문 등) 내에서만 사용하능한 변수이다. 열거형(Enum)은 여러 개의 상수를 하나의 타입으로 묶어놓은 것이다.
using System;
namespace ConsoleApp2
{
internal class Program
{
static int globalVar = 10; // 전역 변수
enum Days { Sun, Mon, Tue, Wed, Thu, Fri, Sat }; // 열거형
static void Main(string[] args)
{
int localVar = 20; // 지역 변수
Console.WriteLine(globalVar);
Console.WriteLine(localVar);
Days day = Days.Mon;
Console.WriteLine(day);
}
}
}
< 구조체 Struct >
C#에서 구조체(Struct)는 관련된 데이터를 하나의 복합 데이터 타입으로 그룹화하는 방법을 제공한다.
struct Point
{
public int x, y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public void DisplayPoint()
{
Console.WriteLine($"Point: ({x},{y})");
}
}
static void Main()
{
Point point = new Point(3, 4);
point.DisplayPoint();
}
< Switch문 >
C#에서 'switch'문을 사용하면 어러 가지 경우에 따른 작업을 처리할 수 있다.
static void Main()
{
int number = 2;
switch(number)
{
case 1:
Console.WriteLine("Number is 1");
break;
case 2:
Console.WriteLine("Number is 2");
break;
default:
Console.WriteLine("Number is not 1 or 2");
break;
}
}
< While문 Do While문 >
C#에서 'while'문과 'do while'문을 사용하여 조건에 따라 반복 작업을 처리할 수 있다.
static void Main()
{
int number = 1;
while(number <= 5)
{
Console.WriteLine(number);
number++;
}
number = 1;
do
{
Console.WriteLine(number);
number++;
}
while(number <= 5);
}
< Foreach문 >
C#에서 foreach문을 사용하여 컬렉션의 모든 요소를 순회할 수 있다..
static void Main()
{
int[] numbers = new int[5] {1, 2, 3, 4, 5};
foreach(int number in numbers)
{
Console.WriteLine(number);
}
}
< 클래스 Class 필드 속성 >
C#에서 클래스(Class)는 객체를 생성하는 템플릿이며, 필드는 클래스 내의 변수를, 속성은 클래스 내의 메소드를 정의하는 데 사용된다.
class Program
{
public class Car
{
private string color; // 필드
public string Color // 속성
{
get { return color; }
set { color = value; }
}
}
static void Main()
{
Car car = new Car();
car.Color = "Red";
Console.WriteLine(car.Color);
}
}
< 클래스 정적 Static 상수 Const >
C#에서 클래스 내의 멤버를 'static'으로 선언하면, 그 멤버는 클래스의 인스턴스가 아닌 클래스 자체에 속하게 된다. 'const'는 상수를 선언하는 데 사용되며, 선언과 동시에 초기화 되어야 하고, 그 값을 변경할 수 없다.
class Program
{
public class Circle
{
public const double PI = 3.14; // 상수
public static int count = 0; // 정적 필드
public Circle()
{
count++;
}
}
static void Main()
{
Console.WriteLine($"PI: {Circle.PI}");
Circle c1 = new Circle();
Circle c2 = new Circle();
Console.WriteLine($"Created {Circle.count} circles");
}
}
< 클래스 메소드 정적 메소드 참조형 Out >
C#에서 클래스 메소드는 특정 클래스의 인스턴스에 연결되어 작동하며, 정적 메소드는 클래스 자체에 연결되어 작동한다. out 키워드는 메소드에서 여러 값을 반환할 때 사용된다.
class Program
{
public class Calculator
{
public static void Multiply(int a, int b, out int result)
{
result = a * b;
}
}
static void Main()
{
int result;
Calculator.Multiply(3, 4, out result);
Console.WriteLine(result);
}
}
< 속성 정의 >
C#에서 속성(Property)은 클래스, 구조체, 인터페이스의 멤버로, 외부에서 접근할 수 있는 값이다. get과 set 접근자를 사용하여 속성 값을 읽거나 변경할 수 있다.
class Program
{
public class Student
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
static void Main()
{
Student student = new Student();
student.Name = "John Doe";
Console.WriteLine(student.Name);
}
}