오늘은 string을 다루는 문제들을 풀었다. 이전까지 배열 문제들만 풀어서인지 배열로 바꾸어서 푸는 비효율적인 방식을 많이 썼지만, 이 문제들을 풀며 string 메소드에도 익숙해졌다.
소문자로 된 단어(문자열)가 입력되면 그 단어의 가운데 문자를 출력하는 프로그램을 작성하세요. 단 단어의 길이가 짝수일 경우 가운데 2개의 문자를 출력합니다.
나는 일단 인자로 받은 문자열을 split을 이용해 배열로 만들고, 그 배열의 길이를 2로 나누어 가운데 값을 구한 다음 그 값을 answer라는 빈 배열로 push하고, return할 때 answer에 join("")을 사용하는 방식으로 문제를 풀었다. 배열을 다루는데 익숙해서 일단 string을 배열로 바꾸어 문제를 푼 것이다. 전체 코드는 다음과 같다.
function solution(s) {
let answer = [];
const sToArr = s.split("");
const mid = Math.floor(sToArr.length / 2);
if (sToArr.length % 2 === 0) {
answer.push(sToArr[mid - 1], sToArr[mid]);
} else {
answer.push(sToArr[mid]);
}
return answer.join("");
}
원하는 대로 동작하긴 하지만 다소 아쉬운 점이 있다. string을 굳이 배열로 바꿀 필요 없이, string 메소드를 이용해서 푸는 편이 더 좋았을 것 같다. 이 문제의 경우 substring과 substr을 사용하면 훨씬 간단했다. 아래는 substring을 사용한 풀이다.
function solution2(s) {
let answer;
let mid = Math.floor(s.length / 2);
if (s.length % 2 == 1) answer = s.substring(mid, mid + 1);
else answer = s.substring(mid - 1, mid + 1);
return answer;
}
위의 코드보다 확실히 간결하다.
substring의 문법은 다음과 같다.
str.substring(indexStart[, indexEnd])
indexStart - 반환문자열의 시작 인덱스
indexEnd - (옵션) 반환문자열의 마지막 인덱스로, 포함하지 않음.
마지막 인덱스는 포함하지 않기 때문에 (mid, mid+1) 처럼 넣어주었다.
substr을 쓰면 (약간이지만) 코드가 더 짧아진다.
function solution3(s) {
let answer;
let mid = Math.floor(s.length / 2);
if (s.length % 2 == 1) answer = s.substr(mid, 1);
else answer = s.substr(mid - 1, 2);
return answer;
}
이 문제를 통해 string 메소드를 공부하게 되서 좋았다.
소문자로 된 한개의 문자열이 입력되면 중복된 문자를 제거하고 출력하는 프로그램을 작성하세요. 제거된 문자열의 각 문자는 원래 문자열의 순서를 유지합니다.
이 문제는 일단 실패한 코드부터 적겠다. 나는 또 split()으로 문자열을 쪼갠 배열을 만들었고(이쯤되면 split 중독자인듯) for문을 통해 i와 j값을 비교해서 동일할 경우 j 값을 splice()로 없애는 방식을 사용했다. 그런데 조건을 잘못 설정해서 i와 j값이 동일하면 모든 값이 splice되게 코드를 작성해버렸다. 빈 배열만 덩그라니 return~ 물론 이 방식도 잘 다듬으면 풀 수는 있겠지만, 그냥 indexOf()를 쓰는 해결방식이 나을 듯하다. 아래는 내가 처음 작성했던 코드다. (return값은 당연하게도 아무 것도 없다..)
function solution(s) {
let answer = s.split("");
for (let i = 0; i <= answer.length; i++) {
for (let j = 1; j <= answer.length; j++) {
if (answer[i] === answer[j]) {
answer.splice(answer[j]);
}
}
}
return answer.join("");
}
이걸 더 다듬지 않고, 그냥 indexOf()를 쓰는 방식을 사용했다.
function solution2(s) {
let answer = "";
for (let i = 0; i < s.length; i++) {
if (s.indexOf(s[i]) === i) answer += s[i];
}
return answer;
}
indexOf('A')를 사용하면, 'A'가 최초로 등장하는 index를 반환한다. 그러니까 이 코드는 'A'가 처음 등장한 인덱스와 A의 인덱스를 비교해서 동일할 경우 answer에 값을 더해주는 코드다.
N개의 문자열이 입력되면 중복된 문자열은 제거하고 출력하는 프로그램을 작성하세요. 출력하는 문자열은 원래의 입력순서를 유지합니다.
직전 문제와 다소 유사한 문제다. 전 문제가 하나의 문자열을 받아 그 문자열에서 특정 문자를 제거하는 과정이었다면, 이번엔 배열에 담긴 여러 값 중 중복되는 값을 제거하는 것만 다르다. 똑같이 indexOf를 사용해서 인덱스가 동일할 경우 answer에 값을 더해주면 된다. 이 문제의 경우 배열이기 때문에 filter를 사용한다. filter는 참이 return되는 요소만 따로 뽑아서 새로운 배열화 시킨다. 즉,
answer = s.filter(function (v, i) {
if (s.indexOf(v) === i) return true;
});
이처럼 indexOf(v)와 인덱스가 동일할 경우 true를 리턴하도록 조건문을 작성하면, answer에는 true인 값들이 담겨 새로운 배열을 형성한다. 전체 코드는 다음과 같다.
function solution(s) {
let answer;
answer = s.filter(function (v, i) {
return s.indexOf(v) === i;
});
return answer;
}
문자열이 입력되면 입력된 문자열에 특정 문자 x가 모두 몇 번 들어가는지 출력하는 프로그램을 작성하세요.
이 문제에도 indexOf()를 사용하면 된다. position을 뜻하는 pos라는 변수명을 선언한 뒤 s.indexOf(x)라는 값을 할당한다. 만약 pos가 -1이 아니라면(indexOf()는 해당하는 값이 없을 경우 -1을 리턴한다) answer의 카운트를 증가시키고, indexOf()의 두번째 매개변수를 1 증가시킨다. 이유를 설명하기 전에 indexOf()의 문법을 확인하면 다음과 같다.
str.indexOf(searchValue[, fromIndex])
searchValue :찾으려는 문자열. 아무 값도 주어지지 않으면 문자열 "undefined"를 찾으려는 문자열로 사용.
fromIndex: (옵션) 문자열에서 찾기 시작하는 위치를 나타내는 인덱스 값이다. 기본값은 0이며, 문자열 전체를 대상으로 찾게 됨.
즉, fromIndex를 pos보다 +1 증가시키는 것은, 우리가 방금 찾은 문자열의 뒷부분에서부터 검색을 시작하라는 의미다. (indexOf()는 일치하는 첫번째 값만 리턴하는데, 이 문제에서 우리는 일치하는 값을 모두 찾아야 하기 때문에.)
while문은 조건문이 참일 때 실행되는 반복문이라서, 해당하는 문자열을 모두 찾으면 자동으로 break되어 반복문이 종료된다. 전체 코드는 다음과 같다.
function findIndex(s, x) {
let answer = 0;
let pos = s.indexOf(x);
while (pos !== -1) {
answer++;
pos = s.indexOf(x, pos + 1);
}
return answer;
}