[D3.js] table의 문자열 or 숫자 정렬(수정본)

in #dclick5 years ago (edited)

[D3.js] table의 문자열 or 숫자 정렬(수정본)



지난 시간으로 table post를 마무리 하려고 했는데 치명적 문제가 발생했네요. 지난 방식으로 하면 정렬이 문자 or 숫자가 한자리면 상관없는데 한자리 이상이면 이게 문자열 정렬인지 숫자 정렬인지 명확하지 않고 문자열 정렬으로 진행 되는 것 같더군요. 즉, 숫자의 경우 1로시작하는 숫자가 크고 2로 시작하는 숫자 작을 때 작은 순으로 정렬한다면 2가 먼저 나와야 하는데 1로 시작하는 숫자가 먼저 나오게 되는 치명적 문제를 갖고 있네요. 그래서 숫자 정렬과 문자열 정렬를 구분하여 정렬이 이루어지도록 수정했습니다.

1. table 정렬 주의



위 post로 정렬을 진행할 경우 한자리 문자 or 숫자의 경우는 정상적으로 출력 됩니다. 하지만 두자리 이상의 경우는 각 자리의 순차적 비교이기 때문에 문자열은 상관없는데 숫자의 경우는 작은수 순서로 정렬 할 경우 이상한 정렬이 발생합니다.

.on('click', function (d) {
  if (sortstate) {
    rows.sort(function(a, b) { return b[d] > a[d]; });
    sortstate = false;
  } else {
    rows.sort(function(a, b) { return b[d] < a[d]; });
    sortstate = true;
  }
});

위 코딩으로 정렬을 시도하면 다음과 같은 결과를 얻게 됩니다.

위 실험에서 a 쪽을 오름차순 or 내림차순으로 정렬을 시키면 보시는 것처럼 20이란 숫자가 중간에 배치되게 됩니다. 원래는 11200->702->20 or 20->702->11200순으로 정렬을 해야 하는데 숫라고 인식않고 이 자체를 문자열 비교가 이루어지는 것 같더군요.

2. 문제 해결


숫자형 정렬과 문자열 정렬을 구분하여 정렬을 해야 합니다.

.on('click', function (d) {
  sortstate = !sortstate;
  rows.sort(function(a,b){
    if(isNaN(a[d])){
      if (sortstate) return b[d] > a[d]; 
      else return a[d] > b[d];
    }else{
      if (sortstate) return b[d] - a[d]; 
      else return a[d] - b[d];
    }
  });
});

위와 같이 isNaN()값으로 문자열인지 숫자형인지를 구분하여 정렬을 시도하니깐 정상적으로 정렬이 이루어지네요. 지난 시간에 정렬을 몇가지 표현했는데 그 안에 숫자 정렬이 들어 있었더군요. 이렇게 해서 해결 했네요.

3. 테스트


[data.csv]

이름,a,b,c
홍길동,11200,90,1910
강감찬,702,12100,720
김수로,20,620,95

[전체소스]

<body>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css">
<script type="text/javascript" src="http://d3js.org/d3.v5.min.js"></script>

<script type="text/javascript">
d3.csv("data.csv").then(function(data){
      var sortstate = true;          
      var title = d3.keys(data[0]); 

      var table = d3.select('body').append('table')
                     .attr("class","table");
      var thead = table.append('thead');
      var tbody = table.append('tbody');

      var header = thead.append('tr')
                       .selectAll('th')
                       .data(title).enter()
                       .append('th')
                       .text(function (d) {return d;})
                       .on('click', function (d) {
                         sortstate = !sortstate;
                         rows.sort(function(a,b){
                           if(isNaN(a[d])){
                             if (sortstate) return b[d] > a[d]; 
                             else return a[d] > b[d];
                           }else{
                             if (sortstate) return b[d] - a[d]; 
                             else return a[d] - b[d];
                           }
                         });
                       });
     var rows = tbody.selectAll('tr').data(data)
                     .enter()
                     .append('tr');

     var cells =  rows.selectAll('td')
                      .data(function (d) {
                               return title.map(function (title) {
                                     return { 'title': title, 'value': d[title]};
                               });
                      })
                      .enter()
                      .append('td')
                      .text(function (d) { return d.value;});
});
</script>
</body>

[결과]
이제야 원하는 정렬이 되었네요.

마무리


table 정렬 post를 수정할까도 생각했는데 정렬이 틀린 것은 아니고 지난 post의 정렬은 한자리일때는 문자 or 숫자는 구분하지 않고 정렬을 하기 때문에 정상적으로 출력했었고요. 원리를 이해하는 위한 post이기 때문에 그냥 뒀네요. 그 원리를 이해했기에 문제가 발생했을 때 바로 수정이 될 수 있었네요.


Sponsored ( Powered by dclick )

dclick-imagead

Sort:  

짱짱맨 호출에 응답하여 보팅하였습니다.

방문해주셔서 감사합니다.

원리 이해가 핵심 이네요... 그래야 어디서 문제가 발생해도 해결점을 찾을수 있으니까요. 세상 모든 일에 적용 되는 말이네요.
크리스마스 스팀 고래의 꿈 복사.jpg

그쵸!
공공데이터를 불러와서 출력했는데 갑자기 정렬이 비정상적으로 되더군요.
다행히 정렬을 몇가지 정리해놓은 것 중에 하나는 숫자정렬이 정상적으로 되고 하나는 문자열정렬이 되어서 쉽게 해결할 수 있었네요.
뭐든지 어떻게 해서 이게 돌아가는지만 알면 쉽게 문제의 원인과 해결방향을 잡을 수 있는 것 같아요.

테니블을 정리하는 기능이네요. 잘 뱌워두면 유용하게 쓰일일이 있을 듯합니다.

알아두면 나중에 써먹을 날이 오겠죠.

Coin Marketplace

STEEM 0.30
TRX 0.12
JST 0.032
BTC 64172.03
ETH 3144.93
USDT 1.00
SBD 3.85