【问题标题】:Trying to sort a custom JavaScript object尝试对自定义 JavaScript 对象进行排序
【发布时间】:2011-03-23 00:49:51
【问题描述】:

我不太擅长 JS,但到目前为止我还挺过来了。我正在创建一种复杂的 JS 对象并想要对其进行排序。对象的结构如下所示:

cart.attributes = [
  {
    Attribute,
    Value
  }
  ...
];

我正在创建一个独特的属性,它告诉我用冒号任意分隔的 3 件事:
(产品 ID):(产品数量迭代器):(属性名称)
产品数量迭代器只是意味着,如果我有 3 个相同的产品,我在属性方面谈论的是 3 个中的哪一个。每个属性都有一个值。

问题正如您从打印输出中看到的那样,没有组织。我想先按(产品 ID)对这些结果进行排序,然后按(数量迭代器),然后按(名称)的字母顺序。

这是一个打印出来的对象,使用下面的方法打印出来,然后是结果。

用于打印结果的代码

$.each(cart.attributes, function(attr, value) {
  console.log("Attr: "+attr);
  console.log("Value: "+value);
});

结果

«Attr» 46913872:2:Size
«Value» 10
«Attr» 46913872:2:Hollow-to-Hem
«Value» 57"
«Attr» 46913872:1:Hips
«Value» 34"
«Attr» 46913872:2:Bust
«Value» 34"
«Attr» 46913872:2:Dress Color (hex)
«Value» #FFFFFF
«Attr» 46913872:2:Rush Cut
«Value» Super Rush Cut - 6 weeks
«Attr» 46913872:1:Extra Length
«Value» 5"
«Attr» 46913872:2:Hips
«Value» 34"
«Attr» 46913872:1:Waist
«Value» 29"
«Attr» 46913872:2:Waist
«Value» 23"
«Attr» 46913872:2:Dress Color (name)
«Value» White
«Attr» 46913872:1:Rush Cut
«Value» Super Rush Cut - 6 weeks
«Attr» 46913872:1:Sash Color (name)
«Value» Lipstick
«Attr» 46913872:2:Sash Color (hex)
«Value» #000000
«Attr» 46913872:1:Size
«Value» 14
«Attr» 46913872:1:Hollow-to-Hem
«Value» 58"
«Attr» 46913872:1:Bust
«Value» 35"
«Attr» 46913872:1:Sash Color (hex)
«Value» #B6064C
«Attr» 46913872:1:Dress Color (hex)
«Value» #F9C8D0
«Attr» 46913872:1:Dress Color (name)
«Value» Tea Rose
«Attr» 46913872:2:Extra Length
«Value» 5"
«Attr» 46913872:2:Sash Color (name)
«Value» Black

【问题讨论】:

    标签: javascript arrays sorting object


    【解决方案1】:

    好的,从下面的 cmets 中我可以更清楚地了解对象是什么。

    假设对象如下所示:

    cart.attributes = {
        '46913872:2:Size' : 10,
        '46913872:2:Hollow-to-Hem' : 57
        // ...
    }
    

    它不是数组,因此无法排序。但是你可以整理出来打印。

    在普通的旧javascript中你可以这样做:

    // First get all keys:
    var keys = [];
    for (var n in cart.attributes) {
        if (cart.attributes.hasOwnProperty(n)) {
            keys.push(n);
        }
    }
    
    // now sort the keys:
    keys.sort(function(a,b){
        attr_a = a.split(':');
        attr_b = b.split(':');
    
        // sort by product ID:
        if (parseInt(attr_a[0],10) < parseInt(attr_b[0],10)) return -1;
        if (parseInt(attr_a[0],10) > parseInt(attr_b[0],10)) return 1;
        // sort by quantity:
        if (parseInt(attr_a[1],10) < parseInt(attr_b[1],10)) return -1;
        if (parseInt(attr_a[1],10) > parseInt(attr_b[1],10)) return 1;
        // finally sort by name:
        if (attr_a[2] < attr_b[2]) return -1;
        if (attr_a[2] > attr_b[2]) return 1;
        return 0;
    })
    
    // now print out the object in key-sorted-order:
    for (var i=0; i<keys.length; i++) {
        console.log("Attr: "+keys[i]);
        console.log("Value: "+cart.attributes[keys[i]]);
    }
    

    【讨论】:

    • 谢谢@slebetman。事实证明,该对象并没有真正的“属性”和“值”项,这些只是我称之为解释的原因。我应该提到:/ 对象只是,cart.attrubutes = [ { '46913872:2:Size', '10' }, { '46913872:2:Hollow-to-Hem', '57"' } / / ... ] 谢谢。
    • 这没有意义,这不是一个有效的 javascript 对象。你的意思是:cart.attributes = ["'46913872:2:Size','10'", "'46913872:2:Hollow-to-Hem','57\" " " // ... ] ?跨度>
    • 是的。这将是它形成slebetman的方式。每个 cart.attribute 都来自一个 HTML 元素: 不过,我将 3 个东西放入键中,所以我可以用更多信息填充它。
    • 这是 Firebug 中属性列表的屏幕截图。我只需要这个有组织的,而不是重组的。谢谢!截图 » grab.by/5EXw
    • 啊,好吧,所以 cart.attributes 不是一个数组,它是一个对象。你应该知道对象中的东西实际上是无序的。所以没有排序这回事。我猜您想对其进行排序以用于显示目的?
    【解决方案2】:

    您应该能够根据对象属性对对象数组进行排序,方法是编写如下自定义排序函数:

    function customSortByPID(a,b) {
      if (a.ProductID > b.ProductID)
      {
          return 1;
      }
      else if (a.ProductID < b.ProductID)
      {
          return -1;
      }
      return 0;
    }
    

    其中 ProductID 是您的对象的一个​​属性。你可以这样称呼它:

      myArray.sort(customSortByPID);
    

    这至少应该让您开始了解如何编写自定义排序函数。请注意,JavaScript 不是强类型的,这可能导致意外的排序行为(将 int 视为字符串)。

    ** 免责声明 ** 我没有测试上述任何内容,这只是我的想法。

    【讨论】:

    • 这是正确的方向,说明可以通过比较器。但他的问题远不止于此。他正在处理一个设计非常糟糕的对象......我正在输入一个答案......
    • 谢谢你们。胡安,你写得不好的对象是对的。
    【解决方案3】:

    首先,理解对象的结构真的很难。这是它的样子吗?

    [
      {  "46913872:2:Size" : 10 },
      {  "46913872:2:Hollow-to-Hem": 57},
      {  "46913872:1:Hips" : "34"}, ...
    ]
    

    看起来你希望它排序

    [
      {  "46913872:1:Hips" : "34"}, // all ids are the same here, but this index is 1
      {  "46913872:2:Hollow-to-Hem": 57}, // index is 2 but Hollow comes before Size
      {  "46913872:2:Size" : 10 },
    ]
    

    如果我了解您的对象结构,则以下解决方案有效。就像 ThatSteveGuy 所说,您可以将比较器传递给您的排序方法。由于对象如此复杂,这就是您要做的

    attributes.sort(function(a, b){
      // Make sense of your objects a and b. See the inner function defined below
      var newA = improveObject(a);
      var newB = improveObject(b);
    
      if (newA.id > newB.id) { return 1; }
      if (newA.id < newB.id) { return -1; }
      // id is the same, check index
      if (newA.index > newB.index) { return 1; }
      if (newA.index < newB.index) { return -1; }
      // index is the same, check name
      if (newA.name > newB.name) { return 1; }
      if (newA.name < newB.name) { return -1; }
      // it's the same thing 
      return 0;
    
      // Turns {  "46913872:2:Size" : 10 }
      // into {id: 46913872, index: 2, name: "Size", value: 10}
      function improveObject(obj) {
        for (var key in obj) {
          var pieces = key.split(":");
          return {
            id: parseInt(pieces[0]),
            index: parseInt(pieces[1]),
            name: pieces[2],
            value: obj[key];
          };
        }
      }
    });
    

    但是,这个对象真的没有意义。我会敦促你重新考虑它的结构。即使我没有完全理解你的对象(你应该已经列出了对象的实际 json),这个例子告诉你所有你需要知道的关于在 js 中排序的知识。

    【讨论】:

    • 胡安,非常感谢。这正是我一直在寻找的。我将花一点时间来消化这一点,然后发布我是如何从一开始就创建对象的。也许您可以帮助我以更好的方式创建对象。
    • 这是 Firebug 中属性列表的屏幕截图。我只需要这个有组织的,而不是重组的。谢谢!截图 » grab.by/5EXw
    • 我理解这个对象。如果你想帮助重组它,你必须告诉我在排序后你将如何使用这个数组。彻底解释这个对象的来源以及你将如何处理它。不确定在哪里发布后续问题的最佳方式是因为您在 cmets 中被限制为 500 个字符。也许是一个新问题?
    • Juan,与其让我重组我所拥有的,你介意调整你的 sort() 函数以使其与我在屏幕截图中显示的内容正常工作吗?现在它没有排序,我 99.9% 确信它与改进对象()有关。谢谢!
    • 什么不起作用?它适用于我上面显示的数组。我不介意帮忙,但我们需要付出一些努力。你试过调试吗?插入一些console.logs,至少告诉我们比较器中有哪些步骤是错误的。让我们知道哪个部分不起作用。另外请将整个数组粘贴到这里,我不可能重新输入整个屏幕。
    【解决方案4】:

    如果您将多个值放在一个由分隔符分隔的字符串中,那么您首先就错过了创建对象的意义。结构应该是,

    cart.attributes = [
        {
            attributes: {
                id: "46913872",
                quantityIterator: 2,
                name: "Dress Color"
            },
            value: "57",
        },
        // repeat for each product
    ];
    

    创建一个从编码字符串创建对象的函数是微不足道的。用':'分割字符串,并分别记录每一部分。

    function makeProduct(key, val) {
        var parts = key.split(':');
    
        var attrs = {};
        attrs.productId = parts[0];
        attrs.quantityIterator = parts[1];
        attrs.name = parts[2];
    
        return { attributes: attrs, value: val};
    }
    

    示例用法:

    makeProduct("46913872:2:Bust", 34); 
    

    返回对象:

    {
        attributes: {
            name: "Bust",
            productId: "46913872",
            quantityIterator: "2"
        },
        value: 34
    }
    

    answer 中列出了按多个字段对对象进行排序的通用方法。

    【讨论】:

    • 我不认为这是正确的对象,为什么你需要一个内部属性对象,我只是将四个属性打到对象中,但这在我的脑海中仍然没有意义因为我不知道迭代器是什么
    • 感谢大家的帮助。我遵守 Shopify 的规则 - 一种电子商务产品。我正在使用一堆 HTML 元素 通过购物订单传递自定义信息。从技术上讲,我有点欺骗系统并且传递的不仅仅是“key”,因为 key 不仅描述了名称,还描述了 id 和数量迭代器。
    • 数量迭代器:假设我要购买 3 件相同的衬衫,但在每件衬衫上我想要不同的定制字母组合。 'IDs' 会是一样的,'name' 会是一样的,比如说“monogram”,而 'quantityIterator' 会是 1,然后是 2,然后是 3。这清楚 Juan 了吗?
    • 这是 Firebug 中属性列表的屏幕截图。我只需要这个有组织的,而不是重组的。谢谢!截图 » grab.by/5EXw
    • @Mike - 截图很有帮助。即使 HTML 元素中的属性以字符串形式编码,您仍然可以在 JavaScript 对象中单独表示每个值,并在需要时使用 toString 函数将其转换为 "a:b:c" 形式。在所有其他时间,它都保持在对象形式中。
    【解决方案5】:

    这样的东西效果很好,你可以很容易地定义一个函数来包装它,并给定比较属性的 jQuery 对象排序:

        var $jobj = jQuery( '.jcss' ); // your selector here
        var $jarr = [];
    
        $jobj.each( function () {
            $jarr.push( jQuery( this ) );
        } );
    
        $jarr.sort( function ( a, b ) {
            var attr = {}; // your comparison attribute here
            attr.a = parseInt( a.data( 'priority' ) || 0 );
            attr.b = parseInt( b.data( 'priority' ) || 0 );
            return attr.a < attr.b ? -1 : attr.a > attr.b ? 1 : 0;
        } );
    
        $jobj = jQuery( jQuery.map( $jarr, function ( obj, i ) {
            return obj[0];
        } ) );
    
        // whatever you need to do here
        $jobj.css( { 'text-decoration': 'blink' } );
    

    【讨论】:

      猜你喜欢
      • 2019-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-21
      • 2018-05-12
      • 2010-12-21
      相关资源
      最近更新 更多