# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
from collections import deque
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
# N, M을 공백으로 구분하여 입력받기
n, m = map(int, input().split())
# 2차원 리스트의 맵 정보 입력받기
graph = []
for i in range(n):
graph.append(list(map(int ,input())))
# 이동할 네 방향 정의(상, 하, 좌, 우)
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
# BFS 소스코드 구현
def bfs(x, y):
# 큐(Queue) 구현을 위해 deque 라이브러리 사용
queue = deque()
queue.append((x,y))
# 큐가 빌 때까지 반복
while queue:
x, y = queue.popleft()
# 현재 위치에서 네 방향으로의 위치 확인
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
# 미로 찾기 공간을 벗어난 경우 무시
if nx < 0 or ny < 0 or nx >= n or ny >= m:
continue
# 벽인 경우 무시
if graph[nx][ny] == 0:
continue
# 해당 노드를 처음 방문하는 경우에만 최단 거리 기록
if graph[nx][ny] == 1:
graph[nx][ny] = graph[x][y] + 1
queue.append((nx,ny))
# 가장 오른쪽 아래까지의 최단 거리 반환
return graph[n - 1][m - 1]
# BFS를 수행한 결과 출력
print(bfs(0, 0))
해당 문제를 풀다가 pycharm을 깔고 실행해보기위해서 깔고 reboot를 실행했는데 이전에
pythontutor에서 풀던 문제를 날려버리는 바람에 나의 답안은 버리게 되었다. 하지만 해당 방식은 dfs 방식이였기 때문에 위 방식이 답안이기 때문에 올바른 방식이다. 위 방식으로 한번 풀어보니 놀랍도록 멋진 코드인거 같다.
n, m = map(int, input().split())
ice = [[0]*m for _ in range(n)]
visit = [[0]*m for _ in range(n)]
result = 0
def dfs(x, y):
dirs = [(-1,0), (0, -1), (1, 0), (0, 1)]
visit[y][x] = 1
for dir in dirs:
xd = x + dir[0]
yd = y + dir[1]
if xd>=0 and xd<m and yd >=0 and yd <n:
if visit[yd][xd] == 0 and ice[yd][xd] == 0:
dfs(xd, yd)
for i in range(n):
str1 = input()
for j in range(len(str1)):
ice[i][j] = int(str1[j])
for i in range(n):
for j in range(m):
if ice[i][j] == 0 and visit[i][j] == 0:
result += 1
dfs(j, i)
print(result)
오늘은 테이블에 행을 추가 하는 것이 아니라면 아이디를 수정하지 못하게 막는 기능을 찾아봤습니다.
일반적으로 특정 속성을 편집하지 못하게 막는 것은 간단하게 할 수 있지만 특정 상태에서는 가능하게 특정 상태에서는 불가능하게 하는 것은 조금 복잡한 문제였습니다. 인터넷을 잘 찾아보니 isNew()라는 함수가 눈에 띄었습니다. isNew는 테이블의 행의 상태가 create인지 edit인지 구별할 수 있는 기능을 제공합니다. 따라서 해당 함수를 사용해서 평소에는 ID 값을 편집하지 못하게 막고 행을 추가할 때만 아이디 값을 수정할 수 있게끔 했습니다.
isNew를 사용한 코드
edit function (e) {
console.log(EDIT, e.model, e.model.isNew(), e.model.id, e.model._defaultId);
if (!e.model.isNew()) {
if (e.container.find("input").attr("name") == "GROUPID") {
this.closeCell();
}
}
오늘아래와 같은 방식으로 문제를 해결하였다. 하나의 테스트케이스만으로 검증하여서 진짜 맞는 코드인지 분간하기가 어렵다.
내가 푼 풀이
n, m = map(int, input().split())
x, y, dir = map(int, input().split())
visited = [[0]*m for _ in range(n)]
field1 = [[0]*m for _ in range(n)]
dirs = [(0, -1), (1, 0), (0, 1), (-1, 0)]
result = 1
visited[y][x] = 1
for i in range(n):
list1 = list(map(int, input().split()))
for j in range(len(list1)):
if list1[j] == 1:
field1[i][j] = 1
def dfs(x, y, d,time):
global result
d -= 1
if d <0:
d = 3
xd = x + dirs[d][0]
yd = y + dirs[d][1]
if xd>=0 and xd <m and yd>=0 and yd<n:
if visited[yd][xd] != 1 and field1[yd][xd] !=1:
result +=1
visited[yd][xd] = 1
time = 0
dfs(xd, yd, d, time)
else :
if time >= 4:
return
else:
dfs(x, y,d, time +1)
else:
if time >= 4:
return
else:
dfs(x, y,d, time +1)
dfs(x, y, dir, 0)
정답
n , m = map(int, input().split())
d = [[0] * m for _ in range(n)]
x, y, direction = map(int, input().split())
d[x][y] = 1
array = []
for i in range(n):
array.append(list(map(int, input().split())))
dx = [-1, 0, 1, 0]
dy = [0, 1, 0 ,-1]
def turn_left():
global direction
direction -= 1
if direction == -1:
direction = 3
count = 1
turn_time = 0
while True:
turn_left()
nx = x + dx[direction]
ny = y + dy[direction]
if d[nx][ny] == 0 and array[nx][ny] == 0:
d[nx][ny] = 1
x = nx
y = ny
count += 1
turn_time = 0
continue
else:
turn_time += 1
if turn_time == 4:
nx = x - dx[direction]
ny = y - dy[direction]
if array[nx][ny] == 0:
x = nx
y = ny
else:
break
turn_time = 0
print(count)
해당 강의를 통해 이해한걸 정리해보면, 객체지향 프로그래밍 언어에서 사용하는 데이터 타입과 데이터베이스에서 사용하는 데이터 타입은 매칭되지 않는다. 그렇기 때문에 데이터베이스에 데이터를 요청하거나 보낼 때 데이터 타입 변환을 해줘야 하는데 이러한 작업은 매우 귀찮은 작업이고 시간이 많이 들어간다 따라서 데이터베이스에서 받은 데이터 타입을 객체지향 언어에서 이해할 수 있는 데이터 타입으로 변환해주는 것이 orm의 역할이라 볼 수 있다.
데퍼를 사용함으로써 얻을 수 있는 이점을 몇가지 알아보면서 마무리 하겠다.
데퍼를 사용하는 이유중 주요한 이유는 빠르다는 것이다. 현재 재직중인 회사에서도 Entity Framework에서 Dapper로 변경을 하였는데 이유는 데이터를 조회시 한번에 가져와야되는 데이터의 수가 증가함에 따라 속도가 느려저서 속도를 개선할 필요성이 필요해서였다.
그리고 코드 라인 수가 감소한다는 이점도 있는Dapper에게 단순히 파라미터와 쿼리문만 주면 되기 때문으로 보인다.
해당 문제를 해커랭크에서 풀어보았습니다. 해당 문제는 해쉬로 푸는 문제지만 이번 문제의 경우 집합이 유리해보여서 set을 사용하였습니다.
해당 문제의 코드는 아래와 같습니다.
def twoStrings(s1, s2):
# Write your code here
s1_set = set()
isSub = False
answer = 'NO'
for str1 in s1:
s1_set.add(str1)
for str2 in s2:
if str2 in s1_set:
answer = 'YES'
break
return answer
해당문제를 풀면서 긴가민가 했던 부분이 있는데 스트링을 포문으로 그냥 range를 안쓰고 문자열로만으로 가능할지 의문이였는데 시도해보니 잘되는 것을 확인할 수 있었습니다.
위와 같이 진행하고 있는 작업은 브랜치를 새로 만드는 것입니다. develop 브랜치를 따로 만들어 사용하는 이유는 아직 변경사항 개발이 완료되지는 않았지만 커밋하여 구성원과 코드 공유를 하기 위해서입니다. master 브랜치는 실제로 배포가 준비된 코드만 올라가야되기 때문에 master 브랜치로 현재 개발중인 코드를 커밋하지 않습니다. develop 브랜치를 완성하였으면 master 브랜치와 병합을 하여 master 브랜치에 develop 브랜치를 반영하여 줍니다.
다시 본화면으로 돌아오면 develop 브랜치가 생성된 것을 확인할 수 있습니다. 그럼 develop 브랜치를 더블클릭하면 develop 브랜치로 넘어가서 작업할 수 있습니다.
이제 코드 작업을 한 뒤 깃 크라켄으로 돌아오면
아래와 같이 되는데 우측에서 원하는 파일들만 골라서 커밋을 따로따로 진행할 수도 있습니다.
커밋을 완료하였다면 push를 통해 깃허브에 반영할 수 있습니다. push는 되도록이면 모든 커밋을 한다음 마지막에 하는 것이 좋은데 가끔 실수하여 커밋을 되돌려야 할 때가 있습니다. 그때 push가 되지 않은 상황이라면 undo 기능을 통해 되돌릴 수 있습니다.
이제 developer 브랜치에서 개발이 완료되었으면 master 브랜치와 병합해주도록 합시다.
kendoGrid를 위해 사용되는 schema와 schema는 어떤 기능이 있는지 살펴보겠습니다.
schema
서버에서 보낸 응답을 파싱 하여 KendoGrid에 어떻게 데이터를 보여줄지 그리고 편집은 어떻게 할지 알려 줍니다.
schema.groups
그룹을 포함하는 서버 응답의 필드 응답에서 그룹을 반환하기 위해 호출되는 함수로 설정할 수 있습니다.
해당 옵션은 serverGrouping option에 true 값을 할당해야 사용할 수 있습니다.
위 내용은 공식 문서를 번역한 설명입니다. 내용이 조금 어려우니 아래 예시를 참조해주세요
직접 사용한 예를 보여드리겠습니다.
groups를 이용하여 아래 이미지와 같이 테이블을 ISVALID 속성의 값이 N인지 Y인지로 그룹을 만들었습니다.
위와 같이 사용하기 위한 코드를 설명하겠습니다. 우선 스키마 밖에서 그룹을 만들 때 구분 지어줄 필드를 지정합니다.
group: [{ field: "ISVALID" }]
저는 그룹을 지어줄 필드로 ISVALID를 선택했습니다.그리고 스키마 안에서 serverGrouping, groups 필드에 아래 코드 블록의 값을 넣으면 됩니다.
serverGrouping: true,
groups: "groups"
해당 설정이 끝나면 위 이미지처럼 ISVALID로 그룹화된 테이블을 확인할 수 있습니다.
schema.data
데이터 항목이 포함된 서버 응답 필드. 응답에 대한 데이터 항목을 반환하기 위해 호출되는 함수로 설정할 수 있다고 공식 문서에 나와있습니다.
해당 함수는 현재 아래와 같이 사용하고 있습니다.
data: "Data"
data에 "Data"라고 값을 할당해주는 이유는 서버 측 Response에 그리드에 표시에줄 값들이 있는 변수 를 매핑해주는 것입니다. 서버측의 리턴 타입을 보면 아래와 같습니다.
Resoponse라는 클래스에 Data라는 변수에 그리드에 표기할 값들을 담아 클라이언트에 전달합니다.
Response값에 그리드에 표기할 값만 담는다면 위와같이 매핑 할 필요가 없지만 Response에 여러 변수를 사용한다면 매핑해주어야 합니다.
schema.total
총 데이터 항목 수를 포함하는 서버 응답의 필드. 응답에 대한 총 데이터 항목 수를 반환하기 위해 호출되는 함수로 설정할 수 있습니다.
스키마에 total 속성을 지정하지 않은 경우
스키마에 total 속성을 total: "Count"와 같이 지정한 경우 아이템의 인덱스와 총계수를 페이지 우측 하단에 나타냅니다.
schema.parse
서버 응답을 parse 에서 사전 처리하거나 구문 분석할 때 사용합니다. 해당 기능을 사용한 예시를 보여드리겠습니다. 아래 화면은 parse를 사용하기 전입니다. 저는 parse 기능을 사용해서 아이템 ID 값들에 아이템을 붙이고 수량은 각 수량마다 100을 더하여 보겠습니다.
아래 화면은 제가 원하는 것을 구현한 화면입니다. 아이템 ID에는 각 아이템 ID마다 아이템이라고 붙어있고 수량은
100씩 증가한 것을 확인할 수 있습니다.
서버의 데이터를 사용하기 전 파싱 하기 위해 사용한 함수는 아래와 같습니다.
parse: function (response) {
var boms = [];
for (var i = 0; i < response.Data.length; i++) {
var bom = {
ITEMID: "아이템" + response.Data[i].ITEMID,
ISVALID: response.Data[i].ISVALID,
QTY: response.Data[i].QTY + 100
};
boms.push(bom);
}
response.Data = boms;
return response;
}
위와 같이 사용하기 위해서 파라미터 response 가 어떤 식으로 메서드로 들어오는지 확인하여야 합니다.
response 파라미터 값을 확인하기 위해 디버깅에 있는 조사식을 활용하였습니다.
위와 같이 ITEMID와, QTY 등의 값은 response의 data에 array형식으로 들어가 있음으로 response.Data 와 같은 형식으로 값에 접근할 수 있습니다.
schema.model
모델 객체를 통해서 속성의 자료형을 변경하거나 밸리데이션 체크 등의 기능을 수행할 수 있습니다.
예를 들어 ID 값을 사용자가 함부로 바꾸면 여러 가지 문제가 발생할 수 있습니다. 따라서 아래와 같이 해당 필드의 edit 여부를 허용해줄지 설정해줄 수 있으며 데이터의 올바른 입력을 위해서 validation check도 할 수 있습니다.
- 아이템ID의 경우 editable 값을 False로 할당하였기 때문에 편집이 되지 않아야 됩니다. 따라서 위 화면처럼 편집이 불가능하게 됩니다.
- QTY와 같은 경우 required값을 True로 주었습니다. 따라서 위와같이 공백을 입력할 경우 경고창이 나타나게 됩니다.
ex2
model: {
id: "ProductID",
fields: {
ProductID: {
//this field will not be editable (default value is true)
editable: false,
// a defaultValue will not be assigned (default value is false)
nullable: true
},
ProductName: {
//set validation rules
validation: { required: true }
},
UnitPrice: {
//data type of the field {number|string|boolean|date} default is string
type: "number",
// used when new model is created
defaultValue: 42,
validation: { required: true, min: 1 }
}
}
}
2번째 예제는 공식문서의 예제입니다. 해당 예제를 통해 알수있는 점은 지정한 속성의 type과 기본 값 그리고 벨리데이션을 설정해줄 수 있습니다.
schema.aggregates
테이블의 원하는 속성을 선택해서 집계 함수를 적용하고 해당 결과를 Json 형태로 리턴해주는 객체입니다.
aggregate를 사용하려면 serverAggregates 값을 true로 바꿔주어야 됩니다.
schema: {
data: "items",
errors: function(response) {
/* The result can be observed in the DevTools(F12) console of the browser. */
console.log("errors as function", response.errors[0])
return response.errors;
}
}