timo timo - 4 months ago 7
jQuery Question

Sorting list by most matched listitems

I've got a single array that contains at minimum 3, at maximum 5 arrays with objects. My goal is to append these objects in to lists, so my result will consist of 3, 4, or 5 lists. I'm trying to sort these list in a somewhat unconventional matter. I want to match the list items with the position of the list items in the other lists. I then want to put the list item that has to most matches at the top, and the ones with the least matches at the bottem. The lists always contain 10 list items.

So for instance, if "Item 3" is present in all five of the lists, "Item 3" gets moved to position 1 in the list for all the lists. If "Item 21" is present in three of the lists, and no other list item is present in more than three of the lists, "Item 21" gets moved to position 2 in all of the lists that contain "Item 21", and so on.

All list items are objects that can be matched via an

id
. My array could look like the following:

var listsToSort = [
[
{id: 1, name: 'Item 1'},
{id: 3, name: 'Item 3'},
{id: 7, name: 'Item 7'},
{id: 8, name: 'Item 8'},
{id: 9, name: 'Item 9'},
{id: 11, name: 'Item 11'},
{id: 12, name: 'Item 12'},
{id: 16, name: 'Item 16'},
{id: 18, name: 'Item 18'},
{id: 19, name: 'Item 19'}
],
[
{id: 2, name: 'Item 2'},
{id: 3, name: 'Item 3'},
{id: 5, name: 'Item 5'},
{id: 12, name: 'Item 12'},
{id: 14, name: 'Item 14'},
{id: 15, name: 'Item 15'},
{id: 16, name: 'Item 16'},
{id: 18, name: 'Item 18'},
{id: 21, name: 'Item 21'},
{id: 23, name: 'Item 23'}
],
[
{id: 3, name: 'Item 3'},
{id: 4, name: 'Item 4'},
{id: 5, name: 'Item 5'},
{id: 6, name: 'Item 6'},
{id: 9, name: 'Item 9'},
{id: 15, name: 'Item 15'},
{id: 18, name: 'Item 18'},
{id: 20, name: 'Item 20'},
{id: 21, name: 'Item 21'},
{id: 22, name: 'Item 22'}
],
[
{id: 3, name: 'Item 3'},
{id: 9, name: 'Item 9'},
{id: 10, name: 'Item 10'},
{id: 16, name: 'Item 16'},
{id: 18, name: 'Item 18'},
{id: 22, name: 'Item 22'},
{id: 23, name: 'Item 23'},
{id: 24, name: 'Item 24'},
{id: 26, name: 'Item 26'},
{id: 28, name: 'Item 28'}
],
[
{id: 3, name: 'Item 3'},
{id: 9, name: 'Item 9'},
{id: 11, name: 'Item 11'},
{id: 13, name: 'Item 13'},
{id: 15, name: 'Item 15'},
{id: 16, name: 'Item 16'},
{id: 18, name: 'Item 18'},
{id: 25, name: 'Item 25'},
{id: 27, name: 'Item 27'},
{id: 29, name: 'Item 29'}
]
];


The result of this example array, when sorted, would look like the following: example of sorted array

Matched items receive a highlight class. "Gaps" in the list where no items are matched are filled with leftover list items that are not present in any of the other lists.

So to clarify, the matched items are placed at the some list positions across all of the lists.
example with legend

How would I go about sorting the array in this matter?

FIDDLE

Answer

This proposal uses a sort object and a reference to each single object for later reference for filling the arrays. This is done by using the sorted reference and it inserts then an object, if, or null if not.

To maintain the right order, not filled gaps are filled with the objects found at index 10 or greater. When all gap above index 10 are filled, the length of the array is set to 10 and returned.

This solution does not provide a stable result, because the sort oder is not stable with objects with the same count.

raw array before moving values

    0       1       2       3       4 
------  ------  ------  ------  ------
    3       3       3       3       3 fixed part with values
   18      18      18      18      18
    9    null       9       9       9
   16      16    null      16      16
 null      15      15    null      15
 null       5       5    null    null
   11    null    null    null      11
   12      12    null    null    null
 null      21      21    null    null
 null    null      22      22    null
 ------------------------------------ 
 null      23    null      23    null variable part to fill above
    1    null    null    null    null
 null       2    null    null    null
 null    null       4    null    null
 null    null       6    null    null
    7    null    null    null    null
    8    null    null    null    null
 null    null    null      10    null
 null    null    null    null      13
 null      14    null    null    null
   19    null    null    null    null
 null    null      20    null    null
 null    null    null      24    null
 null    null    null    null      25
 null    null    null      26    null
 null    null    null    null      27
 null    null    null      28    null
 null    null    null    null      29

var listsToSort = [[{ id: 1, name: 'Item 1' }, { id: 3, name: 'Item 3' }, { id: 7, name: 'Item 7' }, { id: 8, name: 'Item 8' }, { id: 9, name: 'Item 9' }, { id: 11, name: 'Item 11' }, { id: 12, name: 'Item 12' }, { id: 16, name: 'Item 16' }, { id: 18, name: 'Item 18' }, { id: 19, name: 'Item 19' }], [{ id: 2, name: 'Item 2' }, { id: 3, name: 'Item 3' }, { id: 5, name: 'Item 5' }, { id: 12, name: 'Item 12' }, { id: 14, name: 'Item 14' }, { id: 15, name: 'Item 15' }, { id: 16, name: 'Item 16' }, { id: 18, name: 'Item 18' }, { id: 21, name: 'Item 21' }, { id: 23, name: 'Item 23' }], [{ id: 3, name: 'Item 3' }, { id: 4, name: 'Item 4' }, { id: 5, name: 'Item 5' }, { id: 6, name: 'Item 6' }, { id: 9, name: 'Item 9' }, { id: 15, name: 'Item 15' }, { id: 18, name: 'Item 18' }, { id: 20, name: 'Item 20' }, { id: 21, name: 'Item 21' }, { id: 22, name: 'Item 22' }], [{ id: 3, name: 'Item 3' }, { id: 9, name: 'Item 9' }, { id: 10, name: 'Item 10' }, { id: 16, name: 'Item 16' }, { id: 18, name: 'Item 18' }, { id: 22, name: 'Item 22' }, { id: 23, name: 'Item 23' }, { id: 24, name: 'Item 24' }, { id: 26, name: 'Item 26' }, { id: 28, name: 'Item 28' }], [{ id: 3, name: 'Item 3' }, { id: 9, name: 'Item 9' }, { id: 11, name: 'Item 11' }, { id: 13, name: 'Item 13' }, { id: 15, name: 'Item 15' }, { id: 16, name: 'Item 16' }, { id: 18, name: 'Item 18' }, { id: 25, name: 'Item 25' }, { id: 27, name: 'Item 27' }, { id: 29, name: 'Item 29' }]],
    count = Object.create(null),
    countKeys,
    newList = [], 
    reference;

reference = listsToSort.map(function (a) {
    var o = Object.create(null);
    a.forEach(function (b,i) {
        count[b.id] = (count[b.id] || 0) + 1;
        o[b.id] = b;
    });
    return o;
});
countKeys = Object.keys(count);
countKeys.sort(function (a, b) { return count[b] - count[a]; });
newList = reference.map(function (a) {
    var temp = countKeys.map(function (k) {
            return a[k] || null;
        }),
        i = 0, j = 10;

    while (i < 10) {
        if (!temp[i]) {
            while (!temp[j]) {
                j++;
            }
            temp[i] = temp[j];
            j++;
        }
        i++;
    }
    temp.length = 10;
    return temp;
});

console.log(newList);