function solution(files) {
let head = {};
let num = {};
let answer = [...files];
let result = [];
for (let i = 0; i < files.length; i++) {
let s = 0;
for (let j = 0; j < files[i].length; j++) {
if (isNaN(files[i][j]) && !isNaN(files[i][j + 1])) {
head[i] = files[i].slice(0, j + 1).toLowerCase();
s = j + 1;
} else if (!isNaN(files[i][j]) && isNaN(files[i][j + 1])) {
num[i] = Number(files[i].slice(s, j + 1));
break;
}
}
}
let mapped = answer.map((el, i) => {
return { idx: i, val: el };
});
mapped.sort((a, b) => {
if (head[a.idx] > head[b.idx]) return 1;
if (head[a.idx] === head[b.idx]) {
if (num[a.idx] > num[b.idx]) return 1;
if (num[a.idx] === num[b.idx]) return 0;
if (num[a.idx] < num[b.idx]) return -1;
}
if (head[a.idx] < head[b.idx]) return -1;
});
mapped.forEach((el) => {
result.push(el.val);
});
return result;
}
console.log(
solution([
"img12.png",
"img10.png",
"img02.png",
"img1.png",
"IMG01.GIF",
"img2.JPG",
])
);
isNaN()으로 숫자인지 문자인지 판별을 했는데,
문제는 공백 문자열도 false로 판별한다는 점이었다.
그래서 공백 문자열을 만나면 while문을 순회하면서 공백 문자열을 처리해주었다. 가뜩이나 지저분한 풀이가 더 지저분해졌다.
// 1.
2중 for문을 순회하면서,
j와 j+1 사이에 문자열로 숫자로 나뉘는 지점을 찾는다. 이때 공백문자열을 만나면 while문을 통해서 진짜 숫자를 만날 때까지 j++해준다.
-->> j가 문자고, j+1이 숫자면 head에 넣는다. 이때 key값을 i index로 설정한다. (넣을 때 소문자로 치환해서 넣는다.)
-->> j가 숫자이고, j+1이 문자면 num에 넣는다. 이때도 key값을 i index로 설정한다. (넣을 때 숫자로 치환해서 넣는다.)
// 2.
sort 함수를 쓰기 전에 sort 함수에서 각 a,b의 index를 쓰고 싶어서 맵핑을 진행했다.
// 3.
sort를 돌리면서 head[a.idx]와 head[b.idx]를 비교하면서 오름차순으로 정렬하되, 둘이 같으면 숫자로 비교하기 위해 num[a.idx]와 num[b.idx]을 비교한다. 숫자마저 같으면 0을 return 해서 순서를 건드리지 않는다.
// 4.
mapped를 순회하면서 val 값을 result 배열에 push해준다.
function solution(files) {
let head = {};
let num = {};
let answer = [...files];
let result = [];
// 1.
for (let i = 0; i < files.length; i++) {
let s = 0;
for (let j = 0; j < files[i].length; j++) {
if (isNaN(files[i][j]) && !isNaN(files[i][j + 1])) {
if (files[i][j + 1] === " ") {
while (!isNaN(files[i][j + 1]) && files[i][j] !== " ") {
j++;
}
}
head[i] = files[i].slice(0, j + 1).toLowerCase();
s = j + 1;
} else if (!isNaN(files[i][j]) && isNaN(files[i][j + 1])) {
if (files[i][j] === " ") {
while (!isNaN(files[i][j]) && files[i][j + 1] !== " ") {
j++;
}
}
num[i] = Number(files[i].slice(s, j + 1));
break;
}
}
}
// 2.
let mapped = answer.map((el, i) => {
return { idx: i, val: el };
});
// 3.
mapped.sort((a, b) => {
if (head[a.idx] > head[b.idx]) return 1;
if (head[a.idx] === head[b.idx]) {
if (num[a.idx] > num[b.idx]) return 1;
if (num[a.idx] === num[b.idx]) return 0;
if (num[a.idx] < num[b.idx]) return -1;
}
if (head[a.idx] < head[b.idx]) return -1;
});
// 4.
mapped.forEach((el) => {
result.push(el.val);
});
return result;
}
console.log(
solution([
"img 12.png",
"img10.png",
"img02.png",
"img1.png",
"IMG01.GIF",
"img2.JPG",
])
);
localCompare 메서드를 사용한 풀이
localeCompare(compareString, locales, options)
첫번째 인자로 비교 문자열을 넣어준다.
A.localeCompare(정규표현식)
이렇게 사용하면 될듯.
정규표현식은 아직 너무 어렵다..
\D
: 숫자가 아닌 것,*
: 반복,()
: 그룹처리 이므로
=>(\D*)
: 숫자가 아닌 그룹
반대로
=>([0-9]*)
: 숫자인 그룹
i
는 플래그. ignore case를 표현하여 대상 문자열에 대해 대/소문자 식별하지 않는다는 의미를 갖는다.
A,B[1]은 head를 표현,
A,B[2]는 number를 표현
function solution(files) {
let answerWrap = files.map((file, index) => ({file, index}));
const compare = (a, b) => {
const reg = /(\D*)([0-9]*)/i;
const A = a.match(reg);
const B = b.match(reg);
const compareHead = A[1].toLowerCase().localeCompare(B[1].toLowerCase());
const compareNumber = (a, b) => {
return parseInt(a) > parseInt(b) ?
1 : parseInt(a) < parseInt(b) ?
-1
: 0
}
return compareHead === 0 ? compareNumber(A[2], B[2]) : compareHead
}
answerWrap.sort((a, b) => {
const result = compare(a.file, b.file);
return result === 0 ? a.index - b.index : result;
})
return answerWrap.map(answer => answer.file);
}
정규표현식을 활용한 풀이 2
+
도 반복을 표현함. 1번 이상의 반복
destructuring assignment를 사용해 [fn, head, num]으로 정리
function solution(files) {
const re = /^([a-zA-Z-\. ]+)([0-9]+)(.*)$/
let dict = []
files.forEach((entry, idx) => {
let [fn, head, num] = entry.match(re)
dict.push({fn, head: head.toLowerCase(), num: parseInt(num), idx})
})
return dict.sort((a, b) => {
if (a.head > b.head) return 1
if (a.head < b.head) return -1
if (a.num > b.num) return 1
if (a.num < b.num) return -1
return a.idx - b.idx
}).map(e => e.fn)
}