【问题标题】:How to override JavaScript array sort method?如何覆盖 JavaScript 数组排序方法?
【发布时间】:2011-10-31 04:33:05
【问题描述】:

截至 10 月 31 日星期一,此问题仍未得到更正 (人们错误地回答它,好像我要求修改 array.sort 但我没有问这个)

如何使用 radix-msd 算法覆盖 single 数组(不是 Array.sort)的内置 JavaScript 排序方法?

我有基数 msd 排序的算法,它是

// radix most-significant-bit sort for integers
//arr: array to be sorted
//begin: 0
//end: length of array
//bit: maximum number of bits required to represent numbers in arr
function radixsort (arr, begin, end, bit) {
    var i, j, mask;
    i = begin;
    j = end;
    mask = 1 << bit;
    while(i < j) {
        while(i < j && !(arr[i] & mask)) {
            ++i;
        }
        while(i < j && (arr[j - 1] & mask)) {
            --j;
        }
        if(i < j) {
            j--;
            var tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
            i++;
        }
    }
    if(bit && i > begin) {
        radixsort(arr, begin, i, bit - 1);   //    <=== RECURSIVE FUNCTION
    }
    if(bit && i < end) {
        radixsort(arr, i, end, bit - 1);     //    <=== RECURSIVE FUNCTION
    }
}

而我的 JavaScript 对象数组是:

homes[0].price;
homes[0].address;
homes[0].city;
homes[0].state;
homes[0].zip;

因此,当我调用“homes.sort()”时 - 我希望它使用上面的 radix sort 数组根据 price 对整个 homes[x] 数组进行排序。 我该怎么做?

【问题讨论】:

    标签: javascript sorting overriding overloading


    【解决方案1】:

    您无需覆盖sort function,只需将比较器函数作为参数传递给sort 方法即可。

    参数的函数签名是function (a, b),其中a 是与b 进行比较的项目。

    如果您需要不同的排序实现,请将其设置为不同的函数,而不是覆盖默认行为。您可以使用以下方法对所有数组执行此操作:

    Array.prototype.radixsort = function ( ...params... )
    

    这将允许您调用

    [1,2,3].radixsort(...params...);
    

    或者,您可以向Array 添加一个实用函数:

    Array.radixsort = function ( ...params... )
    

    这将被称为:

    Array.radixsort([1,2,3], ...params...);
    

    【讨论】:

    • 我不想重载/覆盖 Array.sort,只是 Homes.sort
    • N/A - 这个答案不适用,因为我不想覆盖 Array.sort。只有 homes.sort(除非另有明智的建议)。
    【解决方案2】:

    我认为修改Array.prototype.sort非常危险的(因为所有其他可能使用 sort() 的代码都会受到影响)。这是代码:

    //Just use this function like radixsort(homes,0,homes.length,32)
    function radixsort (arr, begin, end, bit) {
        var i, j, mask;
        i = begin;
        j = end;
        mask = 1 << bit;
        while(i < j) {
            while(i < j && !(arr[i].price & mask)) {
                ++i;
            }
            while(i < j && (arr[j - 1].price & mask)) {
                --j;
            }
            if(i < j) {
                j--;
                var tmp = arr[i].price;
                arr[i].price = arr[j].price;
                arr[j].price = tmp;
                i++;
            }
        }
        if(bit && i > begin) {
            radixsort(arr, begin, i, bit - 1);
        }
        if(bit && i < end) {
            radixsort(arr, i, end, bit - 1);
        }
    }
    //If you really want to modify default sort function:
    Array.prototype.sort = function(){
        radixsort(this,0,this.length,32); //Use 'this' to access (get reference) to the array.
    }
    

    【讨论】:

    • 但是如果我做了上面的例子,radixsort 怎么知道对我的数组的 Price 属性进行排序?我看到你让函数假设数组中存在 Price 属性,但我想概括 radixsort 函数不假设 Price 属性。
    • 实际上,OP 从未声称要覆盖 Array.prototype.sort (正如你所说,这显然是危险和愚蠢的!)——他们只是想使用 homes.sort() 语法。通过使用“覆盖”一词,我认为 OP 明确表示希望仅对 home 数组使用排序方法,而不是更改 all 数组的行为。
    • @JiminP(或任何人),如果你能帮我概括一下,这样我就不必将“价格”硬编码到基数排序函数中,我会让这个答案正确/公认。请参阅我上面的评论。
    【解决方案3】:

    扩展 Ray Toal 和 zzzzBov 的讨论:

      function defaultCompare(a, b) {
          var a_str = str(a);
          var b_str = str(b);
          if (a_str < b_str) {
              return -1;
          } else if (a_str > b_str) {
              return 1;
          } else {
              return 0;
          }
       }
    
       homes.sort = function (compare_func) {
           compare_func = compare_func || defaultCompare;
           RadixSort(this, 0, this.length, 64);
       }
    

    上面可能有错别字,但应该是朝着更完整的实现迈出的一步。

    【讨论】:

      【解决方案4】:

      你的问题是问两件事:

      1. 如何在数组上调用sort,但调用Array.sort以外的函数?
      2. 如何让排序算法使用特定字段而不对其进行硬编码?

      第一个问题的答案是在homes对象本身上附加一个sort方法:

      homes.sort = function () {radixSort(homes, 0, homes.length, bit);}
      

      正如其中一位评论者和其他回答者所指出的那样,这样做可能会非常令人困惑。一方面,Arrays.sort 采用第二个参数,它是一个比较函数。基数排序是基于分布的排序,而不是基于比较的排序,因此以这种方式“覆盖”sort 没有多大意义。如果有人将比较函数传入,您将忽略它。

      但是还有另一个问题。您所写的radixSort 不起作用,因为它不比较价格。答案之一是硬编码价格,但您说您不喜欢这种情况。您可以按如下方式解决此问题:添加第五个参数,即字段名称。如果未定义,则使用数组元素本身,否则选择字段。像这样的东西(未测试):

      function radixsort (arr, begin, end, bit, field) {
          var i = begin, j = end , mask = 1 << bit;
          // Use the value of the field at i if present, otherwise the whole element
          var at = function (i) {return field in arr ? arr[i][field] : arr[i]};
          while (i < j) {
              while (i < j && !(arr.at(i) & mask)) {
                  ++i;
              }
              while (i < j && (arr.at(j-1) & mask)) {
                  --j;
              }
              if (i < j) {
                  j--;
                  var tmp = arr[i];
                  arr[i] = arr[j];
                  arr[j] = tmp;
                  i++;
              }
          }
          if (bit && i > begin) {
              radixsort(arr, begin, i, bit - 1);
          }
          if (bit && i < end) {
              radixsort(arr, i, end, bit - 1);
          }
      }
      

      现在你可以说:

      homes.sort = function () {radixSort(homes, 0, homes.length, 64, 'price');}
      

      但是,请记住以下警告:

      CAVEAT:如果price 是浮点值,则基数排序可能不起作用。最好的办法是只使用 Array.prototype.sort 并传入一个比较器以对不同的字段进行排序。

      【讨论】:

      • 不要用新的行为覆盖默认函数,这会给以后的调试带来很大的麻烦。
      • @zzzzBov 我倾向于同意你对sort 的看法,但我不会将其作为一般建议,因为默认函数toString 是荒谬的并且意味着被覆盖。 :) 我知道你的意思。不过,从技术角度来看,这个问题还是有道理的,所以我编辑了答案以解决您的问题。
      • toStringvalueOf 是用作所有对象的通用接口的特殊情况,并且预计会覆盖值。您必须维护该通用界面才能使它们正常工作。你不会从toString 返回一个对象或数字,所以如果你要覆盖sort,你必须让它与现有接口一起工作,这涉及到第一个参数是一个比较器函数。
      • 哈!这就是为什么在这种情况下即使不是不可能也很难。基数排序是分布排序,而不是比较排序,所以非常正确,将 sort 视为通用方法,例如 toStringtoValue 没有任何意义,因为基数排序不需要比较器一点也不。这个问题本身仍然很有趣,因为 OP 试图创建一个特定于对象的方法,但是是的,在这种特殊情况下,这根本不是正确的做法。
      猜你喜欢
      • 1970-01-01
      • 2011-10-16
      • 1970-01-01
      • 1970-01-01
      • 2012-06-14
      • 1970-01-01
      • 2021-12-25
      • 2015-08-03
      • 1970-01-01
      相关资源
      最近更新 更多