7

我正在使用一个电子商务平台,该平台缺乏对我们的产品属性字段选项重新排序的能力。这真的很糟糕,因为要插入一个新选项,您几乎必须删除所有现有选项并重新开始。我正在尝试在客户端进行。这是我正在使用的东西(这个是鞋码):

  • 9 EE
  • 9 1/2 EE
  • 10 EE
  • 10 1/2 EE
  • 11 EE
  • 11 1/2 EE
  • 9 EEEE
  • 9 1/2 天
  • 9 1/2 EEEE
  • 10 EEEE
  • 10 1/2 EEEE
  • 11 EEEE
  • 9天
  • 11 1/2 EEEE

这些实际上是某种<option>形式的文本。值的格式是X Y Z

  • X是一个整数
  • Y是字符串“1/2”,可能不存在
  • Z是一个字母代码,可以是“D”、“E”、“EEE”或“EEEE”,并且可能不存在

上述所需的顺序是这样的:

  • 9天
  • 9 1/2 天
  • 9 EE
  • 9 1/2 EE
  • 9 EEEE
  • 9 1/2 EEEE
  • 10 EE
  • 10 1/2 EE
  • 10 EEEE
  • 10 1/2 EEEE
  • 11 EE
  • 11 1/2 EE
  • 11 EEEE
  • 11 1/2 EEEE

我对 javascript 的sort()函数有所了解,但无法完全理解传递给它的比较函数是如何工作的。到目前为止我有这个:

<select>
    <option>9 EE</option>
    <option>9 1/2 EE</option>
    <option>10 EE</option>
    <option>10 1/2 EE</option>
    <option>11 EE</option>
    <option>11 1/2 EE</option>
    <option>9 EEEE</option>
    <option>9 1/2 D</option>
    <option>9 1/2 EEEE</option>
    <option>10 EEEE</option>
    <option>10 1/2 EEEE</option>
    <option>11 EEEE</option>
    <option>9 D</option>
    <option>11 1/2 EEEE</option>
</select>

我从这个答案中的代码开始:https ://stackoverflow.com/a/667198/398242

$("select").html($("option").sort(function (a, b) {
    return a.text == b.text ? 0 : a.text < b.text ? -1 : 1
}));

像这样对项目进行排序(甚至不适用于第一个标准):

  • 10 1/2 EE
  • 10 1/2 EEEE
  • 10 EE
  • 10 EEEE
  • 11 1/2 EE
  • 11 1/2 EEEE
  • 11 EE
  • 11 EEEE
  • 9 1/2 天
  • 9 1/2 EE
  • 9 1/2 EEEE
  • 9天
  • 9 EE
  • 9 EEEE

我在javascript中看到了 return '11' > '9'false这对我来说毫无意义。

MDN 是这样描述比较函数参数的,我有点明白:

function compare(a, b) {
  if (a is less than b by some ordering criterion)
     return -1;
  if (a is greater than b by the ordering criterion)
     return 1;
  // a must be equal to b
  return 0;
}

...但我不知道如何调整它以满足我的要求。我已经尝试了一些东西,但我只是觉得我在黑暗中拍摄。我试图表明我花了一些时间来尝试理解这个问题。我有兴趣了解更多信息,但现在我只想解决这个问题。

http://jsfiddle.net/DnwJ6/有什么线索吗?

4

6 回答 6

2

按照您想要的顺序将值放入数组中:

var shoeSizes = [ '9 D','9 1/2 D','9 EE','9 1/2 EE', ...]

使用Array.protoype.indexOf对于旧版浏览器使用 shim)来获取数组中匹配文本的索引。使用值的索引进行比较,例如:

function(a,b) {
  return shoeSizes.indexOf(a) - shoeSizes.indexOf(b);
}

如果您需要处理不在数组中的值,请测试indexOf返回的值,如果它是 -1 则替换为默认值。

或者,您可以将大小设置为对象中属性值的名称并分配特定值:

var shoeSizes = { '9 D': 5, '9 1/2 D': 10, '9 EE': 15, '9 1/2 EE': 20, ...};

然后使用比较中的值:

function(a,b) {
  return shoeSizes[a] - shoeSizes[b];
}

或者允许默认值:

function(a,b) {
  return (a in shoeSizes? shoeSizes[a] : 1000) - (b in shoeSizes? shoeSizes[b] : 1000);
}
于 2013-07-10T03:53:26.957 回答
2

由于您已格式化文本,因此一种方法是在比较文本元素之前对其进行规范化。

此解决方案可能不是那么理想,但可以完成工作

$("select").html($("option").sort(function (a, b) {
    return nomalize(a.text) < nomalize(b.text) ? -1 : 1;
}));

function nomalize(val){
    var parts =  val.split(' '), op = '';

    op = parts[0].length == 1 ? '0' + parts[0] : parts[0];
    if(parts.length > 1){
        if(/[a-z]/i.test(parts[1])){
            op += '0/0' + parts[1];
        } else {
            op += parts[1]
        }
    }

    op += parts.length > 2 ? parts[2] : '';
    return op;
}

演示:小提琴

如果有人可以提出任何解决方案来进一步优化它,那就太好了

于 2013-07-10T03:59:57.110 回答
1

您必须了解的第一件事是,这12确实9文本项目而不是数字进行排序要少。那是因为<1> <2>小于<9> <nothing>因为1并且9在这种情况下是“主键”。

您面临的第二个问题是长度(9 1/2)是主键还是宽度(EE)是主键。我怀疑前者会更有意义,所以在此基础上继续。

决定之后,最好的办法是为调用提供排序函数,将每个字符串转换为数值,然后比较该值。例如:

  1. 获取第一个(空格分隔)字段 (9) 并将您的值设置为该字段。
  2. 如果下一个字段存在并且是1/2,则添加0.5到该值。
  3. 如果最后一个字段存在(alpha 字段),只需将其转换为小于某个值0.5并添加它(例如,a-> 0.01、B-> 0.02、...、EEEE-> 0.08 等等)。

最后一个取决于宽度的相对顺序,我选择了典型的美国系统。

您最终得到的是一个指示正确排序的值,然后您的排序函数可以简单地进行数字比较。一个例子如下:

function xlat(s) {
    var s2 = s.split(" ");

    var n = parseInt(s2[0]);
    if (s2.length == 1) { return n; }

    var last = s2[1];
    if (last == '1/2') {
        n = n + 0.5;
        if (s2.length == 2) { return n; }
        last = s2[2];
    }
    var widths = ['A','B','C','D','E','EE','EEE','EEEE','F','G'];
    n = n + widths.indexOf(last) / 100;
    return n;
}

$("select").html($("option").sort(function (a, b) {
    var na = xlat(a.text);
    var nb = xlat(b.text);
    return na == nb ? 0 : na < nb ? -1 : 1;
}));

xlat功能在这里很重要。它首先将大小拆分为 1、2 或 3 个元素的数组,并获取第一个元素的数值。如果第二个和第三个不存在,则返回此值(处理“裸”尺寸,如9or 13)。

否则,它决定它是否是半增量长度 - 如果第二个字段是1/2. 此时,它也会检测是否没有宽度并返回大小。

一旦超过这一点,我们就有了尺寸(整体或一半),last变量保存了宽度。然后我们简单地根据这个大小在数组中的位置添加一个值,适当地修改(除以 100),这样它就不会影响主键。

通过使用您自己的代码,您可以获得(如预期的那样):

9 D
9 EE
9 EEEE
9 1/2 D
9 1/2 EE
9 1/2 EEEE
10 EE
10 EEEE
10 1/2 EE
10 1/2 EEEE
11 EE
11 EEEE
11 1/2 EE
11 1/2 EEEE
于 2013-07-10T04:03:01.603 回答
1

您首先需要定义一个适当的排序键,您可以使用它进行合理的比较;以下函数使用正则表达式来挖掘有用的信息:

function sortkey(val)
{
    var matches = val.match(/^(\d+)( 1\/2)? (\w+)$/),
    number = +matches[1];

    if (matches[2]) {
      number += 0.5; // add "1/2"
    }

    return [number, matches[3]];
}

第一场比赛被转换成一个数字;如果第二个匹配可用,0.5则添加。之后,将最后一个匹配项添加为辅助排序键。返回值是这样的:

[9.5, 'EE']

然后可以将此结构用于您的比较功能:

function compareFunc(a, b) {
    var sa = sortkey(a.text),
    sb = sortkey(b.text);

    if (sa[0] == sb[0]) {
        return sa[1] < sb[1] ? -1 : 1;
    } else {
        return sa[0] < sb[0] ? -1 : 1;
    }
}

应用于您的特定代码:

var $sorted = $('select > option').sort(compareFunc);
$('select').html($sorted);

演示

于 2013-07-10T04:13:47.407 回答
1

看看这个:

$("select").html($("option").sort(function (a, b) {
    var regex = /(\d+)((?: 1\/2)? )([DE]+)/;
    var abreakdown = a.text.match(regex), bbreakdown = b.text.match(regex);
    if (parseInt(abreakdown[1]) === parseInt(bbreakdown[1])) {
        if (abreakdown[3] === bbreakdown[3]) {
            return (abreakdown[2] === bbreakdown[2] ? 0 : (abreakdown[2] < bbreakdown[2] ? -1 : 1));    
        } else {
            return abreakdown[3] < bbreakdown[3] ? -1 : 1;
        }
    } else { return parseInt(abreakdown[1]) - parseInt(bbreakdown[1]); }
}));

它使用正则表达式分解各个部分,然后根据每个组件进行比较。

演示小提琴。

于 2013-07-10T04:16:05.773 回答
1

我看到您已经有了一个可行的解决方案,但只是为了比较(双关语),这是许多其他方法之一(小提琴):

// Make a shoe size sortable as text
function sortableSize( text ) {
    // Split the size into parts separated by spaces
    var parts = text.split( ' ' );
    // The first part is the size number;
    // make sure it is two digits (09,10,etc.)
    if( parts[0].length == 1 )
        parts[0] = '0' + parts[0];
    // If it wasn't a 1/2 size, make it 0/2
    if( parts.length == 2 )
        parts.splice( 1, 0, '0/2' );
    // So '9 EE' becomes '09 0/2 EE'
    return parts.join( ' ' );
}

var $options = $('#sizes option');
$options = $options.sort( function( a, b ) {
    a = sortableSize( a.text );
    b = sortableSize( b.text );
    return a < b ? -1 : a > b ? 1 : 0;
});
$('#sizes').html( $options );

此方法创建每个鞋码的文本表示,可直接作为文本排序。然后它使用这些文本表示进行排序。

于 2013-07-10T04:33:42.003 回答