Cristian Muscalu
Cristian Muscalu

Reputation: 9915

Get an array sorted based on the content of another array

How can I sort the allGames array sorted to have the installedGames first?

const allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
const installedGames = [
    { id: 2, name: 'game2' },
    { id: 3, name: 'game3' }
]

const sorted = allGames.sort((a, b) => {
    return a.id - b.id // but this just sorts by id
});

Basically I want to get this order:

{ id: 2, name: 'game2' },
{ id: 3, name: 'game3' },
{ id: 1, name: 'game1' },
{ id: 4, name: 'game4' }

Upvotes: 4

Views: 148

Answers (7)

Nikhil Aggarwal
Nikhil Aggarwal

Reputation: 28475

You can try following.

Firstly to improve the performance, create a map with key as id and value as its index in installedGames array. Then sort the first array based on the indexes stored in map.

Map second array and create an array of ids. Now sort first array based on the

const allGames = [{ id: 2, name: 'game2' },{ id: 1, name: 'game1' },{ id: 4, name: 'game4' },{ id: 3, name: 'game3' }];
const installedGames = [{ id: 2, name: 'game2' },{ id: 3, name: 'game3' }];

const obj = installedGames.reduce((a,c,i) => Object.assign(a, {[c.id]:i}), {});

allGames.sort((a,b) => {
  let aIndex = obj[a.id], bIndex = obj[b.id];
  return aIndex != undefined ? bIndex != undefined ? aIndex - bIndex : -1 : 1;
});
console.log(allGames);

Upvotes: 2

Salman Arshad
Salman Arshad

Reputation: 272236

The criteria for comparing a and b is as follows:

  • If both items are installed or both items are not installed then item with smaller id first
  • Else (it is guaranteed that one is installed and other is not so) installed item first

const allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
const installedGames = [
    { id: 2, name: 'game2' },
    { id: 3, name: 'game3' }
];
allGames.sort(function(a, b) {
    // findIndex returns quicker than filter
    var ai = installedGames.findIndex(game => game.id === a.id) >= 0;
    var bi = installedGames.findIndex(game => game.id === b.id) >= 0;

    // ai === bi   -> both items are installed or both items are not installed
    // a.id - b.id -> item with smaller id first
    // ai - bi     -> if 1 - 0 then return -1, if 0 - 1 then return +1
    return ai === bi ? (a.id - b.id) : -(ai - bi);
});
console.log(allGames);

Upvotes: 2

oles
oles

Reputation: 176

I think this is the fastest way to solve this problem.

 const allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
const installedGames = [
    { id: 2, name: 'game2' },
    { id: 3, name: 'game3' }
]

const output = [
    ...installedGames,
    ...allGames.filter( io => installedGames.findIndex(il => io.id === il.id) === -1 )
];

Upvotes: 3

Jeremy Thille
Jeremy Thille

Reputation: 26390

let allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
let installedGames = [
    { id: 3, name: 'game3' },
    { id: 2, name: 'game2' },
    
]

// Step 1. sort both arrays

allGames = allGames.sort( (a,b) => a.id - b.id )
installedGames = installedGames.sort( (a,b) => a.id - b.id )

// Step 2. remove installedGames from allGames

const remainingGames = allGames.filter( game => !installedGames.find(g => g.name === game.name) )

// step 3. concatenate both

const sortedGames = installedGames.concat(remainingGames)

console.log(sortedGames)

Also, I'd suggest a model change. Instead of having two distinct arrays, I suggest having only one, and add an installed attribute to your games. This will make your life easier :

const allGames = [
    { id: 2, name: 'game2', installed : true },
    { id: 1, name: 'game1', installed : false },
    { id: 4, name: 'game4', installed : false },
    { id: 3, name: 'game3', installed : true },
]

const sortedGames = allGames.sort((a, b) =>
     +b.installed - +a.installed || a.id - b.id
);

console.log(sortedGames)

Upvotes: 6

Nenad Vracar
Nenad Vracar

Reputation: 122077

You can use sort method and inside findIndex and then check if index is -1 and sort by results.

const allGames = [{ id: 2, name: 'game2' },{ id: 1, name: 'game1' },{ id: 4, name: 'game4' },{ id: 3, name: 'game3' },]
const installedGames = [{ id: 2, name: 'game2' },{ id: 3, name: 'game3' }]

allGames.sort((a, b) => {
  const ai = installedGames.findIndex(({id}) => id === a.id);
  const bi = installedGames.findIndex(({id}) => id === b.id)
  return (bi != -1) - (ai != -1) || ai - bi
});

console.log(allGames)

You could also create object form installed games and sort by that object.

const allGames = [{ id: 2, name: 'game2' },{ id: 1, name: 'game1' },{ id: 4, name: 'game4' },{ id: 3, name: 'game3' },]
const installedGames = [{ id: 2, name: 'game2' },{ id: 3, name: 'game3' }]
const inst = installedGames.reduce((r, {id}, i) => Object.assign(r, {[id]: i}), {})

allGames.sort((a, b) => (b.id in inst) - (a.id in inst) || inst[a.id] - inst[b.id]);
console.log(allGames)

Upvotes: 6

Harish
Harish

Reputation: 1911

you can try this

const allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
const installedGames = [
    { id: 2, name: 'game2' },
    { id: 3, name: 'game3' }
]

const sorted = ((a, b) => {
    return a.id - b.id //this just sorts by id
});
var out  = [...installedGames.sort(sorted), ...allGames.filter(o=> !(installedGames.map(i => i.id).indexOf(o.id) > -1)).sort(sorted)]

console.log(out)

Upvotes: 0

jcubic
jcubic

Reputation: 66590

Here is my try:

const allGames = [
    { id: 2, name: 'game2' },
    { id: 1, name: 'game1' },
    { id: 4, name: 'game4' },
    { id: 3, name: 'game3' },
]
const installedGames = [
    { id: 2, name: 'game2' },
    { id: 3, name: 'game3' }
];

var ids = installedGames.map(x => x.id);

const sorted = allGames.slice().sort((a, b) => {
    var pos_a = ids.indexOf(a.id);
    var pos_b = ids.indexOf(b.id);
    // compare both installed
    if (pos_a !== -1 && pos_b !== -1) {
      return pos_a - pos_b;
    }
    // compare installed and not installed
    if (pos_a != -1) {
      return -1;
    }
    // sort the rest
    return 1;
});
console.log(sorted);

Upvotes: 3

Related Questions