tags:

views:

76

answers:

2

I have four variables of type integer -

var tip_1, tip_2, tip_3, tip_4;

The value of these variables are getting fill by some other logic which is always between 1 to 10. I need to maintain a hash with variable name as "key" and value as "value" by following these rules -

  1. The variable with MAX value should be the first element in the hash and so on. e.g. if tip_1 = 4, tip_2 = 1, tip_3 = 2, tip_4 = 10 then hash should be something like, Hash = {tip_4, 10} {tip_1, 4} {tip_3, 2} {tip_1, 1}

  2. In case of tie following order should be considered - tip_1 > tip_2 > tip_3 > tip_4;

A: 

It's a lot easier to do if you make a real array out of your tips:

var tip_1 = 4, tip_2 = 1, tip_3 = 2, tip_4 = 10;

// create an array so we can sort it
var tips = [
  { key: 'tip_1', value: tip_1 }, 
  { key: 'tip_2', value: tip_2 }, 
  { key: 'tip_3', value: tip_3 }, 
  { key: 'tip_4', value: tip_4 }, 
];

tips.sort(function (a, b) {
  // sort value descending
  if (a.value < b.value) return 1;
  if (a.value > b.value) return -1;
  // if the values are equal, sort by key.
  return a.key > b.key ? 1 : b.key < a.key ? -1 : 0; 
});

// tips is now:
// [{key:"tip_4", value:10}, {key:"tip_1", value:4}, {key:"tip_2", value:2}, {key:"tip_3", value:2}]

// loop over the tips
for (var tip, i=0; tip = tips[i]; i++) {
  console.log(tip.key+": "+tip.value);
}

// Outputs:
// tip_4: 10
// tip_1: 4
// tip_3: 2
// tip_2: 1
gnarf
@gnarf you would have to do parse the key and do a numeric comparison since by default the comparisons will be in lexicographic order and things like `"tip_10" < "tip_8"` will return true.
Anurag
+1  A: 

You can always build your custom objects to retain all information instead of encoding them in indices. Makes sorting easier too.

function Tip(type, value) {
    this.type = type;
    this.value = value;
}

var tips = [];

tips.push(new Tip(3, 4));
tips.push(new Tip(2, 4));
tips.push(new Tip(1, 3));
tips.push(new Tip(4, 10));

tips.sort(function(a, b) {
    // sort first by value, and if equal, then by type (index)
    return (b.value - a.value) || (a.type - b.type);    
});

console.log(tips); // 4=>10​, 2=>4, 3=>4, 1=>3​​​​​​​​​​​​​​​​​

Updated the example.

Anurag
Hi. The logic and this approach works fine if I would take an array as your code. But I am bound to use a hash (Prototype). I am not able to implement the same logic for hash. So, the hash I have is something like -h = new Hash();h.set("tip_1", 4);h.set("tip_2", 2);h.set("tip_3", 1);h.set("tip_4", 2);The default order is tip_1>tip_2>tip_3>tip_4 (in case of tie)After, implementing the logic result Hash should be as -result - [{tip_1, 4}, {tip_2, 2}, {tip_4, 2}, {tip_3, 1}]
Saurabh
You can't order the contents of a hash all by itself. Read the first line of docs on Prototype's [Hash](http://www.prototypejs.org/api/hash) - "it can not guarantee consistent order its elements when iterating". You have to either switch to arrays, or write a wrapper that contains the Hash and also maintains the sorted keys in another array.
Anurag
Thanks. I would appreciate if you provide some example code.
Saurabh
@Saurabh - You have to use an array to maintain order. In the example you have given, you are using an array as well - an array of objects - `[{tip_1, 4}, {tip_2, 2}, {tip_4, 2}, {tip_3, 1}]`. You can write a custom sort method that takes in the hash, and returns an *array* of sorted objects, but that sorted array will not be the same as your original Hash, which basically means you have two separate representations of your data. If that's acceptable then look at @granf's solution, although it needs a little modification to work properly.
Anurag