Wireframe

vimscript의 리스트와 사전

vimscript에서 사전과 리스트를 조작하는 여러 함수들이 있다. 리스트(배열)나 사전을 지원하는 여느 프로그래밍 언어와 개념상 비슷한 도구들을 제공해주고 있다. 차이가 있다면 주류 언어들과는 달리 대부분의 조작이 객체 내부를 변경하는 구성으로 되어 있다는 점이다.

리스트 관련 연산과 함수

:h list-functions를 통해서 전체 목록을 확인할 수 있다.

  • list[i], list[s:e] : 리스트에서 특정 위치 및 범위의 값을 얻는다. 음수를 써서 뒤에서부터 인덱싱할 수 있고, 범위의 한쪽 끝을 생략해서
  • len() / count() : 리스트의 크기 / 특정 값의 개수
  • max(), min() : 원소 중 최대, 최소 값
  • empty() : 빈 리스트인지 확인
  • get(idx, value) : 인덱스 범위를 벗어나더라도 에러없이 값을 조회
  • insert(obj, item [, idx]) : 특정 위치에 값을 삽입. 생략하면 맨 앞에 값을 삽입
  • add(list, el) : 리스트의 끝에 el을 추가한다.
  • list + list / extendnew(list1, list2) : 리스트 끼리는 + 로 연결할 수 있다.
  • extend(list1, list2) : list1에 list2를 연결
  • remove(list, idx) : 특정 위치의 원소를 제거
  • copy(list) / deepcopy(list) : 사본을 생성
  • map(list, expr), mapnew(list, expr): 각 요소를 변형. 특이하게 원본을 바로 변형시키는데, mapnew()는 map을 사본에 적용하여 리턴해줌. 이 때 표현식은 문자열이거나 함수 객체이다.
  • filter(list, expr) : 표현식을 만족하지 않는 원소를 제거한다. (원본 변경)
  • reduce(lilst, func) : 함수를 사용해서 리듀스한다.
  • slice(list, start, end) : 리스트의 부분열을 얻는다. end는 포함하지 않는다.
  • sort(list[, func]) / reverse(obj) : 리스트를 제자리 정렬/뒤집기 한다.
  • uniq(list[, func]) : 연속된 중복 원소들을 제거한다. (원본 변경). 연속되지 않으면 중복되어도 제거하지 않는다.
  • split(str) / join(list[, str]) : 문자열을 리스트로 쪼개거나, 문자열의 리스트를 합친다.
  • index(list, obj) : 특정 원소의 위치를 찾는다. 문자열에서 글자를 찾으려면 stridx()를 쓸 것
  • repeat(item, cnt) : 값을 반복하여 리스트를 만든다.
  • flatten(), flattennew() : 이중 리스트를 풀어서 단일 리스트/사본을 만든다.
  • for el in list : for … in 구문을 사용해서 리스트의 각 원소에 대해서 반복할 수 있다.
  • range(n) : 0…n-1의 리스트를 생성한다.
  • getline(s, e) : 현재 버퍼에서 행번호 s…e 사이의 주어진 구간의 각 행을 리스트로 만든다.

사전 관련

  • dict[key] 로 요소 참조. 키가 문자열이라면 dict.key로 참조가능
  • get(dict, key, value) 를 사용해서 참조할 수 있다. 이때 키가 존재하지 않으면 value가 리턴된다.
  • has_key(dict, key) : 사전에 키가 있는지 확인한다.
  • empty(dict): 빈 사전인지 체크한다.
  • remove(dict, key) : 특정 키를 삭제한다.
  • extend(dict1, dict2[, e]), extendnew(dict1, dict2) : 두 사전을 결합한다. 세 번째 인자는 중복된 키에 대한 처리를 하는데, ‘keep’이면 유지, ‘force’면 교체, ‘error’면 에러 처리한다.
  • filter() / map(), mapnew() : 키, 값 쌍을 통한 맵핑 및 필터(원본변형). mapnew()는 사본을 생성하여 변경한다.
  • max(), min(), count(), len() : 길이, 특정 값의 개수, 최대값, 최소값등
  • keys(d), values(d), items(d) : 키의 리스트, 값의 리스트, 키-값 쌍의 리스트를 리턴
  • 사전에 특별히 함수를 설치하는 것이 가능하다. 첫째로 함수의 이름은 사전.함수() 의 형태여야 한다. 인자 뒤에 dict 키워드를 넣는다. 이제 self로 함수 내에서 사전 자신을 찾을 수 있다.

정렬과 맵핑 관련해서는 조금 더 설명을 써 볼까 한다.

정렬

리스트를 정렬할 때에는 sort() 함수를 쓴다. 원본을 변경하고 변경된 원본을 리턴해준다. 두 번째 인자는 비교함수이거나 정렬 옵션 플래그이다.

정렬 옵션으로 ‘1’, ‘i’를 지정하면 대소문자를 무시하고 정렬한다. ‘n’을 주면 사전순이 아닌 숫자순으로 정렬한다. 사전순에서는 ’11’이 ‘9’보다 먼저 나오지만, 숫자순으로는 ‘9’가 먼저오게 된다. ‘N’옵션은 중간에 숫자가 들어가 있는 경우 그 숫자값을 기준으로 정렬한다.

정렬옵션으로는 함수이름이나 함수가 주어질 수 있다. 이 때는 두 원소를 비교하여 순서를 정하는 함수를 지정한다. 왼쪽, 오른쪽 인자를 비교하여 같으면 0, 작아지면 1, 커지면 -1 이다. 만약 해당 함수가 특정 사전과 연결되어 있다면 그 사전을 세번째 인자로 넘겨줄 수 있다.

원본을 변경하지 않으려면 copy()한 후에 정렬해야 한다.

정렬과 마찬가지로 reverse() 함수 역시 제자리에서 순서를 뒤집는 점에 유의하자. vim의 함수들은 거의 대부분 원본을 변경한다. map(), filter() 함수 역시 기본적으로 원본을 변경한다. 특별히 map의 경우에는 mapnew()가 있다. 비슷하게 flatten() / flattennew() 가 있다.

let fruits = "apple Banana cherry Orange"->split()
echo copy(fruits)->sort()
" Banana Orange apple cherry
echo copy(fruits)->sort('i')
" apple Banana cherry Orange
" 참고로 복사는 copy() 대신 [:] 를 써도 된다.

맵도 정렬과 마찬가지로 기본적으로 원본을 변경한다. 맵핑할 내용은 함수 객체 혹은 표현식을 문자열로 표시한 것이다.

:call map(mylist, '"> " . v:val . " <"')

위 식은 리스트의 각 요소 앞 뒤로 꺾쇠를 붙여서 변경한다. 수식 전체는 홑따옴표로 감싸서 전체가 문자열이 된다는 점에 유의하자. 해당 식 내에서 리스트 요소 값은 v:val 로 표현한다. 사전의 경우에는 키와 값을 모두 사용하는데, v:key, v:val 로 각각 참조된다.

따로 작성한 함수가 있다면 FuncRef 객체를 쓰면 된다. (function('함수이름')의 식으로 생성할 수 있다.) 그외에도 람다식 표현을 쓸 수 있다. 람다식 표현 문법은 다음과 같다.

  1. 식 전체는 중괄호로 감싼다.
  2. { arg -> expr } 의 형태가 된다. 매개 변수가 둘 이상이면 콤마로 구분해줄 수 있다.

람다식을 사용하면 위 예제는 다음과 같이 다시 쓸 수 있다.

:call map(mylist, {x -> "> " . x . " <"})

사전의 경우에는 값만 변경되는 다른 사전이 되는 것이 아니라, 키와 값을 모두 사용하여 생성한 수식의 결과로 만들어지는 리스트가 리턴된다.

Exit mobile version