简体   繁体   中英

Sorting an array of objects for a blockchain like data structure

I have an array of objects that looks the following:

var arr = [
  { id: 1, prev: 0 },
  { id: 4, prev: 3 },
  { id: 3, prev: 2 },
  { id: 8, prev: 7 }
  { id: 5, prev: 4 },
  { id: 7, prev: 6 },
  { id: 6, prev: 5 },
  { id: 2, prev: 1 }
]

I am getting this array from the server and there is no guarantees on the order. I want to sort the array such that, each object is followed by the object whose prev property is the same as the id property of the previous object.

For example,

// Given the following array
var arr = [
  { id: 1, prev: 0 },
  { id: 4, prev: 3 },
  { id: 3, prev: 2 },
  { id: 8, prev: 7 }
  { id: 5, prev: 4 },
  { id: 7, prev: 6 },
  { id: 6, prev: 5 },
  { id: 2, prev: 1 }
]

function compareFn(a, b) {
}

var sortedArray = arr.sort( compareFn );

console.log(sortedArray);
/* Should be
[
  { id: 1, prev: 0 },
  { id: 2, prev: 1 },
  { id: 3, prev: 2 },
  { id: 4, prev: 3 }
  { id: 5, prev: 4 },
  { id: 6, prev: 5 },
  { id: 7, prev: 6 },
  { id: 8, prev: 7 }
]
*/

I have tried the following compareFn()

function compareFn(a, b) {
  return a.id === b.prev ? 1 : -1
}

However this results in:

[
  { 'id': 1, 'prev': 0 },
  { 'id': 3, 'prev': 2 },
  { 'id': 4, 'prev': 3 },
  { 'id': 8, 'prev': 7 },
  { 'id': 5, 'prev': 4 },
  { 'id': 6, 'prev': 5 },
  { 'id': 7, 'prev': 6 },
  { 'id': 2, 'prev': 1 }
]

I am quite certain that this is because of the equality in the sorting function instead of the usual >/</<=/>= but I don't know where the problem is.

I could sort using a loop but I want to better understand how the .sort method works.

Any help would be wonderful.

Thank you

Assuming that the prev values won't be dependably in order (since it's a blockchain, after all):

I wouldn't use the built-in sort for this - it requires a consistent compare function, but each item's position depends on the last sorted item's position. It'd be quite convoluted to use .sort for this. Rather, first create a lookup table (an object indexed by prev ), then iterate starting aa prev of 0, finding the appropriate object in the lookup table, until all objects are in the new array:

 var arr = [ { id: 1, prev: 0 }, { id: 4, prev: 3 }, { id: 3, prev: 2 }, { id: 8, prev: 7 }, { id: 5, prev: 4 }, { id: 7, prev: 6 }, { id: 6, prev: 5 }, { id: 2, prev: 1 } ]; const itemsByPrev = arr.reduce((a, item) => { a[item.prev] = item; return a; }, {}); const sorted = []; let lastId = 0; const { length } = arr; while (sorted.length < length) { const obj = itemsByPrev[lastId]; sorted.push(obj); lastId = obj.id; } console.log(sorted); 

Another bonus of using this method is that it has O(n) complexity, compared to .sort , which has O(n log n) complexity.

Try this:

 // Given the following array var arr = [ { id: 1, prev: 0 }, { id: 4, prev: 3 }, { id: 3, prev: 2 }, { id: 8, prev: 7 }, { id: 5, prev: 4 }, { id: 7, prev: 6 }, { id: 6, prev: 5 }, { id: 2, prev: 1 } ] arr.sort(function(a, b) { return a.id - b.id; }); console.log(arr); 

You could store all items with their previous id as key in a map, get the nodes without parent and iterate these parents and get the children as a sorted array.

 var array = [{ id: 1, prev: 0 }, { id: 4, prev: 3 }, { id: 3, prev: 2 }, { id: 8, prev: 7 }, { id: 5, prev: 4 }, { id: 7, prev: 6 }, { id: 6, prev: 5 }, { id: 2, prev: 1 }], map = array.reduce((m, o) => m.set(o.prev, o), new Map), first = array.reduce((s, { id }) => (s.delete(id), s), new Set([...map.keys()])), result = []; first.forEach(id => { var temp; while (map.has(id)) { result.push(temp = map.get(id)); id = temp.id; } }); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

https://developer.mozilla.org/uk/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

function compareFn(a, b) {
  return a.prev - b.prev;
}

or

function compareFn(a, b) {
  return a.id - b.id;
}

looks like all you need to do is this :

function compareFn(a, b) {
   return a.prev - b.prev
}

As I can see previous value is always less than id. So, Ideally sorting the object by its key will work correctly.

keysSorted = arr.sort(function(a, b) {
    return a.key - b.key;
});

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