JavaScript中对数组进行字母数字排序

7

我正在尝试使用JavaScript对动态创建的SELECT OPTIONS列表进行排序。

由于没有访问源代码的权限,否则我将从服务器端代码进行更改。

这是选择器:

<select class="text12 width_constrained" name="/web/personalisation/request/DesignConsultationRequestFormHandler.addressItem">
<option value="1|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">1 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="3|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">3 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="5|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">5 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="7|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">7 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="9|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">9 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="11|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">11 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="13|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">13 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="15|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">15 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="17|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">17 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="19|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">19 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="21|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">21 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="23|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">23 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="25|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">25 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="27|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">27 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="2|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">2 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="4|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">4 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="6|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">6 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="8|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">8 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="10|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">10 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="12|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">12 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="14|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">14 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="16|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">16 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="18|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">18 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="20|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">20 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="22|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">22 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="24|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">24 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="26|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">26 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>
<option value="28|Marsh Gardens||Southampton, Hedge End|Hampshire|SO30 2XN|United Kingdom|false|false|false|false|false|false|false">28 Marsh Gardens, Southampton, Hedge End, SO30 2XN</option>

我目前正在使用以下内容,但它只能通过自然排序方式按第一个字符进行排序,这种方法不支持字母数字混合排序...

jQuery('document').ready(function() {
var opts = jQuery('form[name=consultationForm] select option');

console.log("options");
console.log(opts);

var arr = opts.map(function(_, o) {
    return {
        t: jQuery(o).text(),
        v: o.value
    };
}).get();

console.log("options post sort");
//arr.sort();


arr.sort(function(o1, o2) {
    return o1.t > o2.t ? 1 : o1.t < o2.t ? -1 : 0;
});

console.log(arr);

});

明显的期望输出是按数字值排序的所有选项,但也允许子集,例如2a,2b,2c。

有人能够提供更多帮助吗?


考虑使用分割函数。 - Daniel A. White
1
“但也允许子集,例如2a、2b、2c。”你是什么意思? - Brewal
那么地址是“1 Marsh Gardens”,“2 Marsh Gardens”...你可以有“1 Marsh Gardens”,“2a Marsh Gardens”,“2b Marsh Gardens”。 - Kimear
6个回答

11

听起来你想要的是自然排序,我在这里找到了这个代码示例:Javascript:文本和数字的自然排序。这将为像2a、2b、2c这样的值以及没有街道编号的值提供正确的排序。

function naturalSorter(as, bs){
    var a, b, a1, b1, i= 0, n, L,
    rx=/(\.\d+)|(\d+(\.\d+)?)|([^\d.]+)|(\.\D+)|(\.$)/g;
    if(as=== bs) return 0;
    a= as.toLowerCase().match(rx);
    b= bs.toLowerCase().match(rx);
    L= a.length;
    while(i<L){
        if(!b[i]) return 1;
        a1= a[i],
        b1= b[i++];
        if(a1!== b1){
            n= a1-b1;
            if(!isNaN(n)) return n;
            return a1>b1? 1:-1;
        }
    }
    return b[i]? -1:0;
}

然后

arr.sort(function(o1, o2) {
    return naturalSorter(o1.t, o2.t);
});

我稍微编辑了TJ的代码示例,这是一个实例:JSFiddle


这对我解决了问题,尽管在 arr.sort 的函数调用中您有一个拼写错误。非常感谢。 - Kimear
谢谢提醒,已经修复好了。 - Bryan

1

当我尝试实现这个时,出现了一个错误:Uncaught TypeError: Object #<Object> has no method 'localeCompare' - Kimear
抱歉,忘记了t键。已将其添加到示例中。 - chiborg
这似乎会随机对输出列表进行排序。 - Kimear
@Kimear - o2.t1 是一个笔误,应该是 o2.t。这样有帮助吗? - Mark Reed

1
我相信如果正确使用,localeSort 可以满足您的需求。如果出于某些原因需要实现自己的排序比较,请尝试以下操作:
arr.sort(function(o1, o2) { 
    return o1.t.split(/(\d+|\D+)/)[1] - o2.t.split(/(\d+|\D+)/)[1] 
} );
split方法创建一个由交替的数字和非数字字符串组成的数组(它们之间有空字符串,我们可以忽略这些空字符串)。数组的第0个元素为空,所以第1个元素是第一个组件——房屋号码,没有多余的字符会使数值转换器将其视为NaN。减法强制将字符串转换为数字,然后你就可以继续进行了。
这个想法可以推广到完整的自然排序,通过检查每个字符串的尽可能多的部分来实现。
arr.sort(function(o1, o2) {
           var a = o1.t.split(/(\d+|\D+)/).filter(function(s){return s!=""});
           var b = o2.t.split(/(\d+|\D+)/).filter(function(s){return s!=""});
           for (var cmp = 0, i = 0; 0 == cmp && i < a.length && i < b.length; i++) {
             var n1 = a[i] - 0, n2 = b[i] - 0;
             if (!isNaN(n1) && !isNaN(n2)) 
               cmp = n1 - n2;
             else if (a[i] < b[i]) 
               cmp = -1;
             else if (a[i] > b[i])
               cmp = 1;
           }
           return cmp;
         })

回答接近正确,但对于没有门牌号的地址反应不佳,并会将其随机放置在地址输出中。 - Kimear

0
如果有人想要一个不包含正则表达式的排序算法,可以使用这个。我认为它会更快,但还没有测试过。
function alphanum(a, b) {
  function chunkify(t) {
    var tz = [], x = 0, y = -1, n = 0, i, j;

    while (i = (j = t.charAt(x++)).charCodeAt(0)) {
      var m = (i == 46 || (i >=48 && i <= 57));
      if (m !== n) {
        tz[++y] = "";
        n = m;
      }
      tz[y] += j;
    }
    return tz;
  }

  var aa = chunkify(a);
  var bb = chunkify(b);

  for (x = 0; aa[x] && bb[x]; x++) {
    if (aa[x] !== bb[x]) {
      var c = Number(aa[x]), d = Number(bb[x]);
      if (c == aa[x] && d == bb[x]) {
        return c - d;
      } else return (aa[x] > bb[x]) ? 1 : -1;
    }
  }
  return aa.length - bb.length;
}

代码片段


0

我修改了脚本,使其能够处理对象(按对象属性进行自然排序)

代码

function alphanumCase(a, b, prop) {
    function chunkify(t) {
        var tz = new Array();
        var x = 0, y = -1, n = 0, i, j;

        while (i = (j = t.charAt(x++)).charCodeAt(0)) {
            var m = (i == 46 || (i >=48 && i <= 57));
            if (m !== n) {
                tz[++y] = "";
                n = m;
            }
            tz[y] += j;
        }
        return tz;
    }

    var aa = chunkify(a[prop].toLowerCase());
    var bb = chunkify(b[prop].toLowerCase());

    for (x = 0; aa[x] && bb[x]; x++) {
        if (aa[x] !== bb[x]) {
            var c = Number(aa[x]), d = Number(bb[x]);
            if (c == aa[x] && d == bb[x]) {
                return c - d;
            } else return (aa[x] > bb[x]) ? 1 : -1;
        }
    }
    return aa.length - bb.length;
}

使用方法

someArray.sort(function(a, b) {
    //sort naturally by the name property (a.name vs b.name)
    return alphanumCase(a, b, 'name');
});

0

我创建了一个fiddle来演示重新排序。我将valuetext属性的值以及解析后的街道号存储在数组中,现在排序更容易了。 有人可能会认为我的代码有点臃肿,可能还有更优雅的方法。

$(document).ready(function () {

    var selectModel = []; // We use this to store all the option data

    $('select.text12 option').each(function () {
        var $this = $(this);
        selectModel.push({
            value: $this.val(),
            text: $this.text(),
            index: parseInt($this.val().split('|')[0], 10) // Make sure it's a number
        });
    });

    selectModel.sort(function (a, b) {
        return a.index - b.index;
    });

    var tempHtml = '';

    for (var i = 0, ii = selectModel.length; i < ii; i++) {
        tempHtml += '<option value="' + selectModel[i].value + '">' + selectModel[i].text + '</option>';
    }

    // Here the option html is recreated
    $('select.text12').html(tempHtml);

});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接