2

I am new to Angular and currently working on a Angular 5 application. I have a requirement to get the next or previous item from a dictionary(model) for next and previous navigation to get the route. I looked into multiple articles and came up with the following method. Let me know whether any other efficient and reliable way to do this. I need to also make sure its sorted by value to make sure it retains the same order between server(api) and client. This will be an important method for our application navigation so I want to make sure there is no browser compatibility issues, no drawbacks and its reliable. Worst case I can go with regular switch case statement, it will be ugly with multiple conditions but will be OK. Let me know your thoughts. Thanks in advance

var dict = {
  "name3": 12,
  "name1": 5,
  "name2": 8
};

var items = sortProperties(dict);
//console.log(items);

var getItem = function(key, i) {

var index = 0;
var stop = true;
for (var j = 0; j < items.length; j++) {  
   
        if (items[j][0] == key) {
            index = j;
            break;// Found it
        }
    }    
console.log(index);
if((index + i) > -1 && (index+i) <items.length)
{
  return items[index+i][0];
}
else
{
 return 'empty';
 }  
}


console.log(getItem("name2",-1));
console.log(getItem("name2",+1));



function sortProperties(obj)
{
  // convert object into array
 var sortable=[];
 for(var key in obj)
  if(obj.hasOwnProperty(key))
   sortable.push([key, obj[key]]); // each item is an array in format [key, value]
 
 // sort items by value
 sortable.sort(function(a, b)
 {
   return a[1]-b[1]; // compare numbers
 });
 return sortable; // array in format [ [ key1, val1 ], [ key2, val2 ], ... ]
}
Vinod
  • 343
  • 1
  • 4
  • 14
  • 2
    you are better off using an array since JavaScript property order is not guaranteed. If you have an object then convert it to an array. – danday74 Sep 20 '18 at 12:43
  • @danday74 does the order in the array remains the same b/w api and client? ie., will it retain the order in the way it was added? Thanks – Vinod Sep 20 '18 at 13:04
  • also if the array is always sorted and the distribution isn't too extreme, you can do some kind of optimistic log(n) lookup (like binary search) instead of blindly iterating through the whole thing. – Touffy Sep 20 '18 at 13:07
  • yes it will retain order guaranteed - when you .push() your are adding to the end - when you .unshift() you are adding to the beginning – danday74 Sep 20 '18 at 13:08
  • to find an object in an array you should be using lodash find like this ... https://stackoverflow.com/questions/31054021/how-to-use-lodash-to-find-and-return-an-object-from-array/38581203#38581203 ... most people in the JS world use lodash - it provides a load of functions which make array manipulation easy and so on - its the most popular JS lib and npm module – danday74 Sep 20 '18 at 13:10
  • @danday74 lodash *was* great. JavaScript has the `find` method built-in since es6, although it only corresponds to the predicate form of the lodash function. Besides, it's only convenient. It doesn't reduce the computational complexity of the lookup. – Touffy Sep 20 '18 at 13:13
  • agreed @Touffy - but for one liners you cannot beat it – danday74 Sep 20 '18 at 13:15
  • @danday74 In my case, my server model is a C# list (from API) which gets converted to a js array in the client. Can I assume the order will be the same in the way it was added to the list? – Vinod Sep 20 '18 at 13:15
  • yup a js list will always retain order – danday74 Sep 20 '18 at 13:17
  • and I'm not sure you understand what I meant by "sorted". Just because `push` always inserts an item at the end, doesn't mean the item *should have been* inserted at the end. `a = [1, 3, 4]; a.push(2)` will result in `[1, 3, 4, 2]` which is no longer sorted. – Touffy Sep 20 '18 at 13:19
  • @Vinod if the C# list is an ordered structure, then I'm pretty sure you'll get the same order in its JSON array representation and the resulting JavaScript array. But if you convert the C# list into an *object* like `dict` in your example, there is no guarantee. – Touffy Sep 20 '18 at 13:22
  • @Touffy Thank you for your suggestions. It helps a lot. I prefer your suggestion of maintaining a next and previous properties on all items in a dictionary and just do a direct lookup in the client. – Vinod Sep 20 '18 at 13:50

1 Answers1

3

According to the spec, there is no intrinsic order of properties in objects. While in practice that order is deterministic, it is a bad idea to rely on that.

Sorting the properties every time you want the next or previous one is about as inefficient as it can get without making it worse on purpose. At least use an array to store your (sorted) entries permanently.

If those operations (next and previous) are the main thing you plan to do with your structure and there can be a lot of items in it, you should use a structure that does the operations cheaply: a doubly-linked list.

If you want both that and cheap direct access, you'll have to pay for it somewhere. One solution would be to use an array or Map for cheap direct access, and maintain next and previous properties on all the items in it to also have linked-list behaviour. You'll pay for it every time you mutate the structure, but that may be okay, especially if it doesn't change often.

Touffy
  • 6,309
  • 22
  • 28
  • Good explanation of the linked list / array – JosephDoggie Sep 20 '18 at 12:53
  • Thanks for the reply. I prefer your suggestion of maintaining a next and previous properties on all items in a dictionary and just do a direct lookup on client. I am planning to store this in a session service so will be reloaded/rebuilt (in web server) only on refresh. Thanks – Vinod Sep 20 '18 at 13:10
  • If you do that, it may be best if you transfer the dictionary in this form: `[[name1, {val1, next, prev}], [name2, {val2, next, prev}}], …]`. Because you can pass that to the `Map` constructor. Maps are a bit nicer than raw objects for this kind of usage (for one thing, they are iterables). If everything is computed server-side, the `next` and `prev` properties can just be the key of the next and previous item, instead of a reference. So if you have already got an entry *item*, you'd get the next one with `dict.get(item.next)` – Touffy Sep 20 '18 at 13:32
  • Oh, and `Map`s do guarantee that the iteration order is the order that the items were inserted in. – Touffy Sep 20 '18 at 13:34
  • @Touffy thanks. I think I just need [[name1, {next, prev}]. I haven't worked with Map so far. I will look into it. if I am storing prev and next value in the same item then I don't need a id to order by and order should not matter anymore. I can do a look up by key ie., name1. Thanks – Vinod Sep 20 '18 at 13:56