简体   繁体   中英

Trying to sort a custom JavaScript object

I'm not too good at JS, but have survived thus far. I'm creating a sort-of complex JS object and wanting to sort it. The object's structure looks like this:

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

I'm creating a unique attribute that tells me 3 things separated arbitrarily by a colon:
(Product ID):(Product QTY Iterator):(Attribute's Name)
The product QTY iterator just means, if I have 3 of the same product, which of the 3 am I talking about in terms of the attribute. Each attribute has then a value.

THE PROBLEM As you'll see from the print-out, there's no organization. I'd like to sort these results first by the (Product ID), then the (QTY Iterator), then alphabetically by (Name).

Here's a print out of the object using the following method to print it out, and then the results.

CODE USING TO PRINT RESULTS

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

RESULTS

«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

Ok from the comments below I got a clearer picture of what the object is.

Assuming the object looks like this:

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

It can't be sorted since it's not an Array. But you can sort it out for printing.

In plain old javascript you can do:

// 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]]);
}

You should be able to sort an array of objects, based on the object attributes, by writing a custom sort function like so:

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

Where ProductID is an attribute of your object. You would call it like this:

  myArray.sort(customSortByPID);

That should at least get you started on how to write custom sort functions. Be aware that JavaScript is not strongly typed, which could lead to unexpected sorting behavior (treating an int like a string).

** DISCLAIMER ** I didn't test any of the above, it's just off the top of my head.

First of all, it's really hard to understand the structure of the object. Is this what it looks like?

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

It looks like you want it to sort to

[
  {  "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 },
]

The following solution works if I understood your object structure. Like ThatSteveGuy said, you can pass a comparator to your sort method. Since the object is so complicated, this is what you would do

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];
      };
    }
  }
});

However, the object really doesn't make sense. I would urge you to re-think its structure. Even if I didn't fully understand your object (you should have listed the actual json for the object), the example tells you all you need to know about sorting in js.

Something like this works well, and you can easily define a function to wrap around it and sort jQuery objects given the comparison attribute:

    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' } );

You are missing the point of creating objects in the first place if you are putting multiple values in a string separated by a delimiter. The structure should instead be,

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

Making a function to create an object from the encoded string is trivial. Split the string by ':' and record each part separately.

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};
}

Example usage:

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

returns the object:

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

A generic way to sort an object by multiple fields is listed in this answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM