【问题标题】:JavaScript Sorting a List with restrictionsJavaScript 对有限制的列表进行排序
【发布时间】:2018-04-21 09:01:28
【问题描述】:

我正在使用 Electron 制作一个应用程序,并有一个客户列表,其中包含他们的姓名和位置。我有一个允许用户添加客户的按钮,但是这样做时表格会显示索引。我有另一个按字母顺序对名称进行排序的按钮,但如果其中有包含索引的行,它会首先显示那些...

我想要的是一些限制,即在排序时将带有 (0)(1) 的行放在列表的末尾而不是开头。

示例:

客户已正确排序,但是当我希望单词在 0 之前时,所有带有 0 的行都排在带有实际单词的行之前。

代码: 出于某种原因,在这段代码 sn-p 中它实际上没有显示 0 或 1 索引,但它仍然在有文本的行之前对没有任何内容的行进行排序...

const back = document.getElementById('back');
const cust = document.getElementById('cust');
const custDiv = document.getElementById('custDiv');
const addCust = document.getElementById('addCust');
const inv = document.getElementById('inv');
const invDiv = document.getElementById('invDiv');
const addItem = document.getElementById('addItem');


// add customer
function appendRowCust() {
  var custList = document.getElementById('custList'), // table reference
    row = custList.insertRow(custList.rows.length), // append table row
    i;
  // insert table cells to the new row
  for (i = 0; i < custList.rows[0].cells.length; i++) {
    createCell(row.insertCell(i), i, 'row');
  }
}
// create DIV element and append to the table cell
function createCell(cell, text, style) {
  var div = document.createElement('div'), // create DIV element
    txt = document.createTextNode(''); // create text node
  div.appendChild(txt); // append text node to the DIV
  div.setAttribute('class', style); // set DIV class attribute
  div.setAttribute('className', style); // set DIV class attribute for IE (?!)
  cell.appendChild(div); // append DIV to the table cell
}


// sort customers 
function sortCustTable() {
  var custList, rows, switching, i, x, y, shouldSwitch;
  custList = document.getElementById("custList");
  switching = true;
  /* Make a loop that will continue until
  no switching has been done: */
  while (switching) {
    // Start by saying: no switching is done:
    switching = false;
    rows = custList.getElementsByTagName("TR");
    /* Loop through all table rows (except the
    first, which contains table headers): */
    for (i = 1; i < (rows.length - 1); i++) {
      // Start by saying there should be no switching:
      shouldSwitch = false;
      /* Get the two elements you want to compare,
      one from current row and one from the next: */
      x = rows[i].getElementsByTagName("TD")[0];
      y = rows[i + 1].getElementsByTagName("TD")[0];
      // Check if the two rows should switch place:
      if (x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) {
        // I so, mark as a switch and break the loop:
        shouldSwitch = true;
        break;
      }
    }
    if (shouldSwitch) {
      /* If a switch has been marked, make the switch
      and mark that a switch has been done: */
      rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
      switching = true;
    }
  }
}
table {
  background-color: black;
  color: white;
} 

tr:nth-child(even) {
  background-color: #656565;
}
tr:nth-child(odd) {
  background-color: #505050;
}

td {
  width: 300px;
  max-width: 300px;
  height: 30px;
  text-align: center;
}
<div id="custDiv">
  <div class="addBtns">
    <button id="addCust" onclick="appendRowCust()">add customer</button>
  </div>

  <div style="width: 355px; margin: 0 auto; height: 50px;">
    <button id="sortCust" onclick="sortCustTable()">sort</button>
  </div>

  <div class="custScroll">
    <table id="custListTop">
      <tr>
        <td contenteditable="false">Customers</td>
        <td contenteditable="false">Main Location</td>
      </tr>
    </table>
    <table id="custList" contenteditable="true">
      <tr>
        <td>Someone</td>
        <td>something</td>
      </tr>
    </table>
  </div>

</div>

【问题讨论】:

    标签: javascript html css list sorting


    【解决方案1】:

    首先,您需要总结一下您的规格是什么。据我了解,它们是这样的:

    • 您的表格需要按字典顺序按第一列排序...
    • 数字或空字符串除外,它们需要在列中排在最后。

    现在,@IrkenInvader 给出的答案是正确的,指出您不需要编写自己的排序算法,但就实施正确有效的解决方案而言,请考虑使用 @987654321 的内置算法@有一些修改:

    function sortCustTable() {
      var custList = document.getElementById('custList');
      var rows = custList.getElementsByTagName('tr');
      var parent = rows[0].parentElement;
      var length = rows.length;
      var data = [], ref, charCodes;
    
      for (var index = 0; index < length; index++) {
        ref = {
          row: rows[index],
          value: rows[index].firstElementChild.textContent.toUpperCase()
        };
    
        if (ref.value === '') {
          ref.value = 'k'; // will sort after everything else, including numbers
        } else if (!isNaN(ref.value)) {
          charCodes = ref.value.split('').map(function (char) {
            return Number(char) + 97; // charCode for 'a'
          });
    
          // for example, '05' would become 'af'
          ref.value = String.fromCharCode.apply(String, charCodes);
        }
    
        data.push(ref);
      }
    
      data.sort(function (a, b) {
        if (a.value > b.value) return 1;
        if (a.value < b.value) return -1;
        return 0;
      });
    
      for (var index = 0; index < length; index++) {
        parent.appendChild(data[index].row);
      }
    }
    

    我选择仅使用 ECMAScript 5 功能,因为您的代码中的注释表明想要支持 Internet Explorer。我注意到您使用的是const,所以如果您觉得这样更容易,请随时使用 ES6 进行修改。

    将它与您的其余代码放在一起,您可以在下面看到它的工作原理。我在表格中添加了更多默认值,让您了解它的工作原理:

    const back = document.getElementById('back');
    const cust = document.getElementById('cust');
    const custDiv = document.getElementById('custDiv');
    const addCust = document.getElementById('addCust');
    const inv = document.getElementById('inv');
    const invDiv = document.getElementById('invDiv');
    const addItem = document.getElementById('addItem');
    
    // add customer
    function appendRowCust() {
      var custList = document.getElementById('custList'), // table reference
        row = custList.insertRow(custList.rows.length), // append table row
        i;
      // insert table cells to the new row
      for (i = 0; i < custList.rows[0].cells.length; i++) {
        createCell(row.insertCell(i), i, 'row');
      }
    }
    // create DIV element and append to the table cell
    function createCell(cell, text, style) {
      var div = document.createElement('div'), // create DIV element
        txt = document.createTextNode(''); // create text node
      div.appendChild(txt); // append text node to the DIV
      div.setAttribute('class', style); // set DIV class attribute
      div.setAttribute('className', style); // set DIV class attribute for IE (?!)
      cell.appendChild(div); // append DIV to the table cell
    }
    
    
    // sort customers 
    function sortCustTable() {
      var custList = document.getElementById('custList');
      var rows = custList.getElementsByTagName('tr');
      var parent = rows[0].parentElement;
      var length = rows.length;
      var data = [], ref, charCodes;
    
      for (var index = 0; index < length; index++) {
        ref = {
          row: rows[index],
          value: rows[index].firstElementChild.textContent.toUpperCase()
        };
    
        if (ref.value === '') {
          ref.value = 'k'; // will sort after everything else, including numbers
        } else if (!isNaN(ref.value)) {
          charCodes = ref.value.split('').map(function (char) {
            return Number(char) + 97; // charCode for 'a'
          });
    
          // for example, '05' would become 'af'
          ref.value = String.fromCharCode.apply(String, charCodes);
        }
    
        data.push(ref);
      }
    
      data.sort(function (a, b) {
        if (a.value > b.value) return 1;
        if (a.value < b.value) return -1;
        return 0;
      });
    
      for (var index = 0; index < length; index++) {
        parent.appendChild(data[index].row);
      }
    }
    table {
      background-color: black;
      color: white;
    } 
    
    tr:nth-child(even) {
      background-color: #656565;
    }
    tr:nth-child(odd) {
      background-color: #505050;
    }
    
    td {
      width: 300px;
      max-width: 300px;
      height: 30px;
      text-align: center;
    }
    <div id="custDiv">
      <div class="addBtns">
        <button id="addCust" onclick="appendRowCust()">add customer</button>
      </div>
    
      <div style="width: 355px; margin: 0 auto; height: 50px;">
        <button id="sortCust" onclick="sortCustTable()">sort</button>
      </div>
    
      <div class="custScroll">
        <table id="custListTop">
          <tr>
            <td contenteditable="false">Customers</td>
            <td contenteditable="false">Main Location</td>
          </tr>
        </table>
        <table id="custList" contenteditable="true">
          <tr>
            <td>Someone</td>
            <td>something</td>
          </tr>
          <tr>
            <td>Somebody</td>
            <td>1</td>
          </tr>
          <tr>
            <td></td>
            <td>1</td>
          </tr>
          <tr>
            <td>0</td>
            <td>1</td>
          </tr>
          <tr>
            <td>someone else</td>
            <td>1</td>
          </tr>
          <tr>
            <td>somebody else</td>
            <td>1</td>
          </tr>
        </table>
      </div>
    
    </div>

    现在,为了弄清楚为什么要这样排序,让我们看看表值以及在排序之前我们如何修改它们:

     Customers     | Main Location
    ---------------+---------------
     Someone       | something
     Somebody      | 1
                   | 1
     0             | 1
     someone else  | 1
     somebody else | 1
    

    我们将丢弃第二列,因为我们不使用它,并将所有客户也设置为大写:

     Customers     |
    ---------------|
     SOMEONE       |
     SOMEBODY      |
                   |
     0             |
     SOMEONE ELSE  |
     SOMEBODY ELSE |
    

    接下来我们检查每个字符串是否为空,如果是,我们给它赋值'k'

     Customers     |
    ---------------|
     SOMEONE       |
     SOMEBODY      |
     k             |
     0             |
     SOMEONE ELSE  |
     SOMEBODY ELSE |
    

    最后,我们修改任何数字,将它们的数值加上 97,并将生成的 charCode 转换为字符:

     Customers     |
    ---------------|
     SOMEONE       |
     SOMEBODY      |
     k             |
     a             |
     SOMEONE ELSE  |
     SOMEBODY ELSE |
    

    按字典顺序排序,我们得到:

     Customers     |
    ---------------|
     SOMEBODY      |
     SOMEBODY ELSE |
     SOMEONE       |
     SOMEONE ELSE  |
     a             |
     k             |
    

    然后放回原始值,我们得到:

     Customers     | Main Location
    ---------------+---------------
     Somebody      | 1
     somebody else | 1
     Someone       | something
     someone else  | 1
     0             | 1
                   | 1
    

    【讨论】:

      【解决方案2】:

      我添加了一种从单元格内容数组中绘制表格的方法。对rows 进行排序并调用drawTableRows 将以rows 数组结束的任何顺序重新创建表。我添加了一些代码以每隔三行插入一次模拟数据,以便可以看到将数字排序到底部。

      这是一个比我通常希望给出的答案更大的变化,但我认为您可能会喜欢看到不同的方法。

      var rows = [[ 'Someone', 'something' ]];
      
      function drawTableRows() {
        var custList = document.getElementById('custList'); // table reference
        custList.innerHTML = '';
        
        for(var i = 0; i < rows.length; i++) {      
          var row = rows[i];
          var tableRow = custList.insertRow(i); // append table row    
              
          for(var j = 0; j < row.length; j++) {      
            createCell(tableRow.insertCell(j), row[j], 'row');      
          }
        }
      }
      
      // add customer
      function appendRowCust(customer = 0, location = 1) {
        //throw in mock data every 3 rows (just a test - remove later)
        if(rows.length % 3 === 0) {
          customer = 'Real customer ' + rows.length;
          location = 'Real location ' + rows.length;
        }
        
        rows.push([customer, location]);
        drawTableRows();
      }
      
      // create DIV element and append to the table cell
      function createCell(cell, text, style) {
        var div = document.createElement('div'), // create DIV element
          txt = document.createTextNode(text); // create text node
        div.appendChild(txt); // append text node to the DIV
        div.setAttribute('class', style); // set DIV class attribute
        div.setAttribute('className', style); // set DIV class attribute for IE (?!)
        cell.appendChild(div); // append DIV to the table cell
      }
      
      function sortCustTable() {
        rows.sort(function(a,b){
          //sort by first column
          var aVal = a[0];
          var bVal = b[0];
          
          //sort by cell content - if content is a number push to bottom.
          if((bVal > aVal) || !isNaN(bVal)) {
            return -1;
          }    
          if((aVal > bVal) || !isNaN(aVal)) {
            return 1;
          }    
          return 0;
        });
        
        drawTableRows();
      }
      table {
        background-color: black;
        color: white;
      }
      
      tr:nth-child(even) {
        background-color: #656565;
      }
      
      tr:nth-child(odd) {
        background-color: #505050;
      }
      
      td {
        width: 300px;
        max-width: 300px;
        height: 30px;
        text-align: center;
      }
      <div id="custDiv">
        <div class="addBtns">
          <button id="addCust" onclick="appendRowCust()">add customer</button>
        </div>
      
        <div style="width: 355px; margin: 0 auto; height: 50px;">
          <button id="sortCust" onclick="sortCustTable()">sort</button>
        </div>
      
        <div class="custScroll">
          <table id="custListTop">
            <tr>
              <td contenteditable="false">Customers</td>
              <td contenteditable="false">Main Location</td>
            </tr>
          </table>
          <table id="custList" contenteditable="true">
            <tr>
              <td>Someone</td>
              <td>something</td>
            </tr>
          </table>
        </div>
      
      </div>

      【讨论】:

        【解决方案3】:

        您可以通过尝试转换为数字并确定当前迭代值是否为整数来过滤掉差异。然后简单地对两个结果集进行排序和连接。

         var list = [0, 2, "2", "0", 1, 2, "a", "b", "c"],
          numeric = list.filter(value => Number.isInteger(+value)),
          alpha = list.filter(value => !Number.isInteger(+value)),
          result = alpha.sort().concat(numeric.sort());
        

        要优化上述内容,您可以过滤一次,如果结果为 false,则推送到单独声明的数组 alpha

           var list = [0, 2, "2", "0", 1, 2, "a", "b", "c"],
           alpha = [],
           numeric = list.filter(value => {
             let torf = Number.isInteger(+value);
             if (!torf) alpha.push(value);
             return torf;
           }),
           result = alpha.sort().concat(numeric.sort());
        

        确定两者之间的差异将是一个微优化,我怀疑在任何情况下都需要这种优化,而前者更加详细和清晰。我的建议是使用第一个选项。

              var list = [0, 2, "2", "0", 1, 2, "a", "b", "c"],
              numeric = list.filter(value => Number.isInteger(+value)),
              alpha = list.filter(value => !Number.isInteger(+value)),
              result = alpha.sort().concat(numeric.sort());
            
            console.log(result);

        【讨论】:

          猜你喜欢
          • 2021-02-03
          • 2015-11-20
          • 1970-01-01
          • 2012-11-09
          • 1970-01-01
          • 1970-01-01
          • 2010-10-14
          • 2014-06-21
          相关资源
          最近更新 更多