5

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

5 Answers 5

5

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]]);
}
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks @slebetman. It turns out that the object doesn't really have the items "Attribute" and "Value", those are just what I call them for explanation. I should have mentioned that :/ The object is just, cart.attrubutes = [ { '46913872:2:Size', '10' }, { '46913872:2:Hollow-to-Hem', '57"' } // ... ] Thanks.
That doesn't make sense, that is not a valid javascript object. Do you mean: cart.attributes = ["'46913872:2:Size','10' ", "'46913872:2:Hollow-to-Hem','57\" " // ... ] ?
Yes. That is going to be the way it's formed slebetman. Each cart.attribute comes from an HTML element: <input name="attributes[key]" value="value" /> I'm putting 3 things into the key though, so I can stuff it with more info.
Here's a screenshot in Firebug of the Attributes list. I just need this organized, not restructured. Thanks! Screenshot » grab.by/5EXw
Ah, ok so the cart.attributes is not an array, it is an object. You should know that things in objects are actually unordered. So there is no such thing as sorting. I'm guessing you want to sort it for display purposes?
|
3

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.

2 Comments

This is in the right direction, explaining that you can pass a comparator. But his problem is deeper than that. He's working with a very poorly designed object... I'm typing an answer...
Thank you both. Juan, you're right with the poorly written object.
3

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.

5 Comments

Juan, thank you so much. This is exactly what I was looking for. I'm going to take a moment to digest this and then post how I created the object from the get-go. Maybe you can help me create the object in a better manner.
Here's a screenshot in Firebug of the Attributes list. I just need this organized, not restructured. Thanks! Screenshot » grab.by/5EXw
I understand the object. If you want help restructuring it, you have to tell me how you're going to use this array after it's sorted. Give a thorough explanation of where this object comes from and what you are going to do with it. Not sure where is the best way to post a follow up question since you're restricted to 500 chars in comments. Maybe a new question?
Juan, rather than me restructure what I've got, do you mind adjusting your sort() function so that it works properly with what I showed you in the screen shot? Right now it doesn't sort, and I'm 99.9% sure it has to do with improveObject(). Thanks!
What doesn't work? It worked for the array I showed above. I don't mind helping but we need to see some effort. Did you try debugging? Insert some console.logs and at least tell us what steps are buggy in the comparator. let us know which part is not working. Also please paste the whole array here, I can't possibly retype that whole screen.
1

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.

6 Comments

I don't think this is the right object, why do you need an inner attributes object, I would just slap the four properties into the object, but that still doesn't make sense in my head since I have no clue what the iterator is
Thank you all for helping. I am conforming to the rules of Shopify - an ecommerce product. I'm passing custom information through a shopping order using a bunch of HTML element <input name="attributes['key']" value="value" />. Technically, I'm cheating the system a bit and passing more than just "key", because key describes not just the name, but the id and quantity iterator.
QUANTITY ITERATOR: Let's say I'm buying 3 of the same shirt but on each shirt I want a different custom monogram. The 'IDs' would be the same, the 'name' would be the same, let's say "monogram" and the 'quantityIterator' would be 1, then 2, then 3. Does that clear it up Juan?
Here's a screenshot in Firebug of the Attributes list. I just need this organized, not restructured. Thanks! Screenshot » grab.by/5EXw
@Mike - the screenshot is very helpful. Even if the attributes in the HTML element are encoded in a string form, you can still represent each value individually in your JavaScript object, and have a toString function that converts it to a "a:b:c" form when needed. All other times, it remains in the object form.
|
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.