Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4주차 과제 구현 #3

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions problem-1/SymbolTableWithArray.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,58 @@
class SymbolTable {
#arr = [];
#size;

constructor() {
this.#size = 0;
}

size() {
return this.#size;
}

isEmpty() {
return this.#size === 0;
}

getKey(key) {
let idx;
this.#arr.forEach((item, arrIdx) => {
if (item.key === key) {
idx = arrIdx;
}
});
Comment on lines +19 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

배열을 순회해서 주어진 키에 해당하는 index를 찾기 위해서 forEach메서드를 활용하셨네요. forEach메서드는 주어진 배열을 모두순회하는 메서드이기 때문에 의도가 다르게 전달될 수 있어요. 여기서는 주어진 키만 찾으면 탐색을 그만둬야 하기 때문이죠. 따라서 for문을 사용해서 찾으면 그만두던지 아니면 findIndex를 사용할 수 있어요.

See also

return idx;
}

put(key, value) {
if (this.#size === 0 || this.getKey(key) === undefined) {
const obj = { key: key, value: value };
this.#arr.push(obj);
this.#size++;
} else if (this.#size > 0 && this.getKey(key) !== undefined) {
// 좀 더 조건식을 고칠 수 있을 거 같은데 널체크나 0 길이 체크 시 계속 || && 에러낸다..
this.#arr[this.getKey(key)].value = value;
}
}
Comment on lines +27 to +36
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

경우에 수를 따져보면 이렇게 될 것 같아요. 이건 조건문으로 만들면 다음과 같아요.

if (this.#size === 0) {
  // size가 0
} else {
  // size가 0이 아님
  if (this.getKey(key) === undefined) {
    // getKey가 undefined
  } else {
    // getKey가 undefined가 아님
  }
}

조건문을 사용할 때는 이렇게 진리표를 만들지 않으면 무조건 헷갈립니다. 어려워요. 놓칠 수가 있어요. 그래서 이렇게 진리표를 만들고 하나하나씩 확인해가면서 해야 빠트리지 않습니다. 각 경우를 테스트 코드를 작성해야 놓치는 버그가 없어요.


get(key) {
const arrKey = this.getKey(key);
console.log(999, this.#arr);
return arrKey === undefined ? undefined : this.#arr[arrKey].value;
}

delete(key) {
const arrKey = this.getKey(key);
if (arrKey !== undefined) {
delete this.#arr[arrKey];
this.#size--;
}
}
Comment on lines +44 to +50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삭제하기 위해서 Array의 해당하는 키를 삭제하고 크기를 줄이셨네요.

Array에서 어떤 값을 삭제하면 한 칸씩 밀어줘야 합니다.

예를들어서 [1, 2, 3, 4, 5]에서 index 2에 해당하는 3을 삭제한다고 해보죠.

delete this.#arr[arrKey];
this.#size--;

만 하게 되면 [1, 2, undefined, 4] 이렇게 됩니다. 그렇게 되면 의도하지 않은 5가 삭제가 되죠?

  delete(key) {
    const arrKey = this.getKey(key);
    if (arrKey !== undefined) {
      // 해당하는 키가 덮어써짐
      for (let i = arrKey; i < this.#size - 1; i++) {
        this.#arr[i] = this.#arr[i + 1];
      }
      
      this.#size--;
    }
  }

그러면 [1, 2, 4, 5]가 되어 3이 삭제가 됩니다.
따라서 배열에서는 값을 삭제하고, 뒤에 배열들을 하나씩 밀어줘야 합니다.


contains(key) {
const arrKey = this.getKey(key);
return arrKey !== undefined;
}
}

module.exports = {
Expand Down
86 changes: 43 additions & 43 deletions problem-1/problem-1.test.js
Original file line number Diff line number Diff line change
@@ -1,126 +1,126 @@
const { SymbolTable } = require('./SymbolTableWithArray');
const { SymbolTable } = require("./SymbolTableWithArray");

test('심볼 테이블은 비어있다', () => {
test("심볼 테이블은 비어있다", () => {
const st = new SymbolTable();

expect(st.size()).toBe(0);
expect(st.isEmpty()).toBe(true);
});

test('심볼 테이블에 아이템을 추가하면 사이즈가 증가한다.', () => {
test("심볼 테이블에 아이템을 추가하면 사이즈가 증가한다.", () => {
const st = new SymbolTable();

const oldSize = st.size();

st.put('foo', 'bar');
st.put("foo", "bar");

const newSize = st.size();

expect(newSize - oldSize).toBe(1);
});

test('이미 있는 키 값에 값을 추가하면 사이즈가 증가하지 않는다.', () => {
test("이미 있는 키 값에 값을 추가하면 사이즈가 증가하지 않는다.", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

const oldSize = st.size();

st.put('foo', 'other');
st.put("foo", "other");

const newSize = st.size();

expect(newSize - oldSize).toBe(0);
});

test('이미 있는 키 값에 값을 추가하면 이전 값을 덮어쓴다', () => {
test("이미 있는 키 값에 값을 추가하면 이전 값을 덮어쓴다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

expect(st.get('foo')).toBe('bar');
expect(st.get("foo")).toBe("bar");

st.put('foo', 'other');
st.put("foo", "other");

expect(st.get('foo')).toBe('other');
expect(st.get("foo")).toBe("other");
});

test('삭제한 키를 조회하면 undefined를 반환한다', () => {
test("삭제한 키를 조회하면 undefined를 반환한다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

expect(st.get('foo')).toBe('bar');
expect(st.get("foo")).toBe("bar");

st.delete('foo');
st.delete("foo");

expect(st.get('foo')).toBeUndefined();
expect(st.get("foo")).toBeUndefined();
});

test('없는 키를 조회하면 undefined를 반환한다', () => {
test("없는 키를 조회하면 undefined를 반환한다", () => {
const st = new SymbolTable();

expect(st.get('foo')).toBeUndefined();
expect(st.get("foo")).toBeUndefined();
});

test('키를 삭제하면 사이즈가 감소한다', () => {
test("키를 삭제하면 사이즈가 감소한다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

const oldSize = st.size();

st.delete('foo');
st.delete("foo");

const newSize = st.size();

expect(newSize - oldSize).toBe(-1);
});

test('없는 키를 삭제하면 사이즈가 감소하지 않는다', () => {
test("없는 키를 삭제하면 사이즈가 감소하지 않는다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

const oldSize = st.size();

st.delete('other');
st.delete("other");

const newSize = st.size();

expect(newSize - oldSize).toBe(0);
});

test('contains 해당하는 키와 값이 존재할 경우 true를 반환한다', () => {
test("contains 해당하는 키와 값이 존재할 경우 true를 반환한다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put("foo", "bar");

expect(st.contains('foo')).toBe(true);
expect(st.contains("foo")).toBe(true);
});

test('contains 해당하는 키와 값이 없을 경우 false를 반환한다', () => {
test("contains 해당하는 키와 값이 없을 경우 false를 반환한다", () => {
const st = new SymbolTable();

expect(st.contains('foo')).toBe(false);
expect(st.contains("foo")).toBe(false);
});

test('심볼 테이블은 키에 해당하는 값을 저장한다', () => {
test("심볼 테이블은 키에 해당하는 값을 저장한다", () => {
const st = new SymbolTable();

st.put('foo', 'bar');
st.put('something', 'that');
st.put('this', 'is');
st.put("foo", "bar");
st.put("something", "that");
st.put("this", "is");

expect(st.get('foo')).toBe('bar');
expect(st.get('something')).toBe('that');
expect(st.get('this')).toBe('is');
expect(st.get("foo")).toBe("bar");
expect(st.get("something")).toBe("that");
expect(st.get("this")).toBe("is");

st.delete('this');
st.delete('something');
st.delete('foo');
st.delete("this");
st.delete("something");
st.delete("foo");

expect(st.get('foo')).toBeUndefined();
expect(st.get('something')).toBeUndefined();
expect(st.get('this')).toBeUndefined();
expect(st.get("foo")).toBeUndefined();
expect(st.get("something")).toBeUndefined();
expect(st.get("this")).toBeUndefined();
});
Loading