{ }codelper

배우기 › Craykon

데이터 · 13

목록 고치기

있는지 묻기, 빼기, 뒤집기, 자리 바꾸기, 같은 값으로 채우기, 복사.

목록은 만든 뒤에도 값을 빼고 순서를 바꿀 수 있어요.
아래 예제는 카드 목록을 복사해 두고, 수 하나가 있는지 물어서 있으면 빼고, 맨 앞 카드를 빼고, 뒤집고, 앞의 두 장을 맞바꿔요.
그리고 고친 목록, 복사해 둔 처음 목록, 0으로 채운 새 목록을 찍어요.

n = 콘솔.줄읽기().수로변환();cards = 콘솔.수들읽기();x = 콘솔.줄읽기().수로변환();original = cards.부분목록(0, cards.개수); // 복사해 둬요만약 (cards.있나(x)){    콘솔.쓰기("yes");    cards.빼기(x); // 값으로 빼기: 처음 나오는 하나만}아니면{    콘솔.쓰기("no");}cards.자리빼기(0); // 자리로 빼기: 0번cards.뒤집기();t = cards[0]; // 자리 바꾸기cards[0] = cards[1];cards[1] = t;blank = 새목록(cards.개수, 0); // 0으로 채운 새 목록콘솔.쓰기(cards);콘솔.쓰기(original);콘솔.쓰기(blank);
stdin
5
30 10 40 10 50
10
stdout
yes
10 50 40
30 10 40 10 50
0 0 0

핵심

  • 있는지 묻기는 참·거짓으로 답해요.
    반복문으로 하나씩 비교하지 않아도 한 줄로 쓸 수 있어요(C는 반복문으로 찾아요).
  • 빼기는 두 가지예요.
    자리로 빼기는 i번 칸을 없애고, 값으로 빼기는 그 값이 처음 나오는 칸 하나만 없애요.
    어느 쪽이든 뒤의 값들이 한 칸씩 앞으로 당겨져요.
    없는 값을 빼려 할 때 벌어지는 일은 언어마다 달라요.
  • 뒤집기는 새 목록을 만들지 않고 그 목록의 순서를 거꾸로 바꿔요.
  • 자리 바꾸기: 두 칸의 값을 맞바꿀 때 a[0] = a[1]부터 쓰면 a[0]의 원래 값이 사라져요.
    임시 변수에 하나를 옮겨 두거나, 한 번에 맞바꾸는 문법을 써요.
  • 같은 값으로 채우기: 0이 n개 든 목록처럼, 크기와 처음 값만 주고 목록을 만들어요.
  • 복사: 08 단원에서 b = a는 같은 목록에 이름을 하나 더 붙일 뿐이라고 했어요.
    원래 목록을 남겨 두려면 고치기 전에 따로 복사해요.
    Python·JavaScript·Java·C#·크레이콘의 이 복사는 한 겹만이에요.
    목록 안에 목록이 든 격자(12 단원)는 복사해도 줄을 함께 쓰니까, 줄마다 따로 복사해요.

언어별로 쓰는 법

Pythonx in a.
값으로 a.remove(x)(없으면 ValueError), 자리로 a.pop(i)나 del a[i].
a.reverse().
a[0], a[1] = a[1], a[0].
[0] * n.
복사는 a.copy()
JavaScripta.includes(x).
자리로 a.splice(i, 1).
값으로 빼는 함수는 없어서 a.indexOf(x)로 자리를 찾아 splice.
a.reverse().
[a[0], a[1]] = [a[1], a[0]].
new Array(n).fill(0).
복사는 [...a]
TypeScriptJavaScript와 같아요
JavaList<Integer>에서 a.contains(x).
자리로 a.remove(i), 값으로 a.remove(Integer.valueOf(x))(없으면 false).
Collections.reverse(a), Collections.swap(a, 0, 1).
new ArrayList<>(Collections.nCopies(n, 0)).
복사는 new ArrayList<>(a).
배열 new int[n]은 처음부터 0으로 차 있어요
C#List<int>에서 a.Contains(x).
값으로 a.Remove(x)(없으면 false), 자리로 a.RemoveAt(i).
a.Reverse().
(a[0], a[1]) = (a[1], a[0]).
Enumerable.Repeat(0, n).ToList().
복사는 new List<int>(a)
C++std::find(a.begin(), a.end(), x)가 a.end()가 아니면 있는 거예요.
찾은 자리를 a.erase(it)로, i번은 a.erase(a.begin() + i)로 빼요.
std::reverse(a.begin(), a.end()), std::swap(a[0], a[1]).
std::vector<int> b(n, 0).
b = a가 곧 복사예요
C배열은 크기가 정해져 있고 이런 함수가 없어요.
반복문으로 찾고, 뺄 때는 뒤의 값들을 한 칸씩 당긴 뒤 개수를 직접 줄여요.
뒤집기는 양 끝에서 맞바꾸고, 맞바꾸기는 임시 변수 t로 해요.
복사는 memcpy(b, a, n * sizeof a[0]) — b = a는 컴파일 오류예요
Craykona.있나(x).
값으로 a.빼기(x)(없으면 false), 자리로 a.자리빼기(i).
a.뒤집기().
맞바꾸기는 임시 변수로.
새목록(n, 0).
복사는 a.부분목록(0, a.개수)

자주 하는 실수

값 1을 빼려 했는데 1번 칸이 빠졌어요Java

List<Integer> a = new ArrayList<>(List.of(1, 2, 3));
a.remove(1);
System.out.println(a);

→ [1, 3] — int를 넣으면 자리로 빼요. 1번 칸의 2가 빠졌어요

값으로 빼려면 a.remove(Integer.valueOf(1)) → [2, 3].
[10, 20, 30]에 a.remove(10)을 쓰면 10번 칸을 찾다가 IndexOutOfBoundsException으로 멈춰요.

없는 값을 빼려 했더니 마지막 값이 빠졌어요JavaScript · TypeScript

const a = [1, 2, 3];
a.splice(a.indexOf(9), 1);
console.log(a);

→ [ 1, 2 ] — 없으면 indexOf가 -1을 주고, splice(-1, 1)은 맨 뒤 칸을 빼요

먼저 있는지 확인해요: const i = a.indexOf(9); if (i !== -1) a.splice(i, 1);

목록을 돌면서 그 목록에서 뺐어요Python · JavaScript · TypeScript · Java · C#

a = [1, 1, 2, 3]
for v in a:
    if v == 1:
        a.remove(v)
print(a)

→ Python은 [1, 2, 3] — 뺀 자리로 다음 값이 당겨져서 두 번째 1을 건너뛰어요. JavaScript의 for...of도 같은 결과예요. Java는 ConcurrentModificationException, C#은 InvalidOperationException으로 멈춰요. 크레이콘의 각각만은 시작할 때의 목록을 따로 떠 놓고 돌아서, 1이 둘 다 빠진 2 3이 돼요

남길 값만 모아 새 목록을 만들거나 전용 함수를 써요: Python a = [v for v in a if v != 1], JavaScript a = a.filter(v => v !== 1), Java a.removeIf(v -> v == 1), C# a.RemoveAll(v => v == 1).

언어마다 다른 점
뒤집기는 그 목록 자체를 바꾸는 명령이라, 결과를 받아 쓰면 안 되는 언어가 있어요.
Python에서 b = a.reverse()라고 쓰면 b는 None이에요.
거꾸로 된 새 목록이 필요하면 Python은 a[::-1], JavaScript는 복사한 뒤 뒤집는 [...a].reverse()를 써요.
그리고 C에서 int *b = a;는 복사가 아니라 같은 배열을 가리키는 이름이에요.
b[0] = 9를 하면 a[0]도 9가 돼요.

연습 문제