셀 수 있는 수량의 순서 있는 열거 또는 어떤 순서를 따르는 요소들의 모음을 튜플(tuple)이라고 합니다. n개의 요소를 가진 튜플을 n-튜플(n-tuple)이라고 하며, 다음과 같이 표현할 수 있습니다.
튜플은 다음과 같은 성질을 가지고 있습니다.
- 중복된 원소가 있을 수 있습니다. ex : (2, 3, 1, 2)
- 원소에 정해진 순서가 있으며, 원소의 순서가 다르면 서로 다른 튜플입니다. ex : (1, 2, 3) ≠ (1, 3, 2)
- 튜플의 원소 개수는 유한합니다.
원소의 개수가 n개이고, 중복되는 원소가 없는 튜플 (a1, a2, a3, ..., an)
이 주어질 때(단, a1, a2, ..., an은 자연수), 이는 다음과 같이 집합 기호 {
, }
를 이용해 표현할 수 있습니다.
예를 들어 튜플이 (2, 1, 3, 4)인 경우 이는
와 같이 표현할 수 있습니다. 이때, 집합은 원소의 순서가 바뀌어도 상관없으므로
는 모두 같은 튜플 (2, 1, 3, 4)를 나타냅니다.
특정 튜플을 표현하는 집합이 담긴 문자열 s가 매개변수로 주어질 때, s가 표현하는 튜플을 배열에 담아 return 하도록 solution 함수를 완성해주세요.
[제한 사항]
{
, }
, ,
로만 이루어져 있습니다.[입출력 예]
s | result |
---|---|
"{{2},{2,1},{2,1,3},{2,1,3,4}}" | [2,1,3,4] |
"{{1,2,3},{2,1},{1,2,4,3},{2}}" | [2,1,3,4] |
"{{20,111},{111}}" | [111,20] |
"{{123}}" | [123] |
"{{4,2,3},{3},{2,3,4,1},{2,3}}" | [3,2,4,1] |
입출력 예에 대한 설명
입출력 예 #3
(111,20)을 집합 기호를 이용해 표현하면 {{111},{111,20}}이 되며, 이는 {{20,111},{111}}과 같습니다.
입출력 예 #4
(123)을 집합 기호를 이용해 표현하면 {{123}} 입니다.
입출력 예 #5
(3, 2, 4, 1)을 집합 기호를 이용해 표현하면 {{3},{3,2},{3,2,4},{3,2,4,1}}이 되며, 이는 {{4,2,3},{3},{2,3,4,1},{2,3}}과 같습니다.
처음에 생각한 풀이
{
→ [
}
→ ]
result
배열에 하나씩 push최종 풀이
result
배열에 하나씩 pushfunction solution(s) {
let str = s;
str = str.slice(1, -1);
let arr = str.split('},{');
arr = arr.map(el => el.replace(/[{}]/g, ''));
arr = arr.map(element => JSON.parse(`[${element}]`));
arr.sort((a, b) => {
return a.length - b.length;
});
const result = arr[0];
if(arr.length < 2) return result;
for(let i = 1; i < arr.length; i++){
for(let j = 0; j < arr[i].length; j++){
if(!result.includes(arr[i][j])) {
result.push(arr[i][j]);
break;
}
}
}
return result;
}
"{{2},{2,1},{2,1,3},{2,1,3,4}}"
형태로 들어오는 문자열에서 맨 앞뒤 중괄호를 잘라냄 → "{2},{2,1},{2,1,3},{2,1,3,4}"
,
가 있기 때문에, ,
로 split은 못 하고, }, {
로 split 해야 됨 → ["{2", "2,1", "2,1,3", "2,1,3,4}"]
{
나 }
가 있으면 제거 → ["2", "2,1", "2,1,3", "2,1,3,4"]
JSON.parse()
를 이용해, 각 문자열을 풀어 배열에 넣어주고, 배열의 배열을 만듦 → [[2], [2,1], [2,1,3], [2,1,3,4]]
sort()
함수 사용 → [[2], [2,1], [2,1,3], [2,1,3,4]]
result
배열의 기본값을 이 정렬된 배열의 0번째 요소로 삼음result
는 현재 [2]
)result
배열을 그대로 반환result
배열에 없는 요소를 차례로 push 해주면 됨function solution(s) {
return JSON.parse(s.replace(/{/g, '[').replace(/}/g, ']'))
.sort((a, b) => a.length - b.length)
.reduce((arr, v, n) => {
if (n) {
return arr.concat(v.filter(f => !arr.includes(f)));
}
return v;
}, []);
}
split()
함수로 배열을 쪼갤 생각이었어서 굳이 중괄호를 소괄호로 바꾸는 의미가 없을 것 같아서 이렇게 풀지 못했는데 생각해 보니까 JSON.parse()
사용하면 배열의 배열로 변환된다...🥹reduce()
의 첫 번째 인자는 콜백 함수고, 두 번째 인자는 배열의 초기값arr
와 현재 요소를 나타내는 v
, 현재 반복 인덱스를 나타내는 n
으로 이루어져 있다.arr
는 내 코드의 result
배열이라고 생각하면 될 것 같다.v
에서 arr
에 포함되지 않는 요소만 필터링해서 배열로 만들고, 그걸 concat()
으로 원래 arr
에 이어주면, 최종적으로 만들어야 하는 배열이 완성된다.const tupleFrom = (str) =>
str.slice(2, -2).split('},{')
.map((it) => toNumbers(it))
.sort(accendingByLength)
.reduce((acc, cur) =>
[...acc, ...cur.filter((it) => !acc.includes(it))], []);
const toNumbers = (str) => str.split(',').map(it => Number(it));
const accendingByLength = (arr1, arr2) => arr1.length - arr2.length;
const solution = (s) => tupleFrom(s);
},{
으로 나눈다.,
로만 split 해도 문제 없이 배열이 쪼개진다.sort()
와 reduce()
는 직전 코드와 유사하게 사용한 것 같다.reduce()
를 잘 써야 알고리즘을 잘할 것 같은데 아직도 너무 어렵다...forEach()
와 map()
의 차이
forEach()
과 map()
둘 다 배열을 순회하면서 인자로 받은 콜백 함수를 실행하지만,forEach()
는 원본 배열을 변경시키지 않고 항상 undefined
를 반환하는 반면,map()
은 해당 콜백 함수를 수행한 새로운 배열을 반환한다!정규표현식 OR 표현법
{
또는 }
면 잡아주는 정규식이 필요했는데, []
로 or를 표현할 수 있다는 것을 알게 되었음replace('{', '').replace('}', '')
이렇게 작성하지 말고, replace(/[{}]/g, '')
이렇게 작성해 주면 한 번에 {
나 }
를 찾아낼 수 있다!return 값에 따른 sort()
함수 동작
sort()
함수는 인자로 들어온 함수의 return 값에 따라 정렬 방식이 달라진다.a
, b
에 대하여,a < b
로 정렬하고,b < a
로 정렬한다.sort()
의 인자로 넣을 함수를 적절히 작성하는 연습을 하자!문제를 풀 때 2중 for문을 reduce()
등으로 변환 가능한지에 대해 고민해 보자...!