Tui
Tui

Reputation: 185

Create a function to sort an array of objects by their values in Javascript

This is an array of objects:

const movies = [
  {
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Die Hard",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
  },
]

I would like to sort them by title and genre.name.

I want to create 2 new arrays, one is sorted by title and the other one is sorted by genre.name.

So far I tried this, but it was clearly wrong:

 const sortMovies = (item) => {
  movies.sort((a, b) =>
   a.item> b.item? 1 : b.item> a.item? -1 : 0
   );
 };

const sortTitle = sortMovies(title);
const sortGenre = sortMovies(genre.name);

Please help me find a solution to this. I really appreciate it!

Upvotes: 1

Views: 675

Answers (4)

KR Tirtho
KR Tirtho

Reputation: 464

A sort higher order function only takes 1/-1 so passing 0 shouldn't work as far as I know.. But if you wanna sort the items as the item provided by the sortMovies function argument you have to do the following:

const movies = [
  {
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Die Hard",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
  },
]

let sortsMovies = (properties) => {
  return movies.sort((a, b) => {
    try {
      const propertyArr = properties.split(".");
      // this gets properties from the end of the object nest
      const props1 = propertyArr.reduce((obj, prop) => obj[prop], a);
      const props2 = propertyArr.reduce((obj, prop) => obj[prop], b);

      return props1 > props2 ? 1 : -1;
    }
    catch (error) {
      console.error('error:', error)
    }
  });
}

const genre = sortsMovies("genre.name")
const title = sortsMovies("title")
console.log('title:', title)
console.log('genre:', genre)

This should sort the Array of Object with the provided property

Upvotes: 1

Nguyễn Văn Phong
Nguyễn Văn Phong

Reputation: 14208

It seems that you want to compare title then genre.name.

So you can combine those criteria in this way

a.title.localeCompare(b.title) || a.genre.name.localeCompare(b.genre.name)

const movies = [
  {
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Die Hard",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "B" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "A" },
  },
];

const sortMovies = (data) => {
  data.sort((a, b) => 
            a.title.localeCompare(b.title)|| a.genre.name.localeCompare(b.genre.name));
}
sortMovies(movies);

console.log(movies);

As you can see, title = Get Out is also sorted by genre.name


Edited

I want to create 2 new arrays, one is sorted by title and the other one is sorted by genre.name.

In case you want to create a generic method

  const sortMovies = (data, getValueByProp) => {
  data.sort((a, b) => 
  {
    const v1 = getValueByProp(a);
    const v2 = getValueByProp(b);
    return v1.localeCompare(v2);
  });
}
sortMovies(movies, (item) => item.title);
sortMovies(movies, (item) => item.genre.name);

const movies = [
  {
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Die Hard",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "B" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "A" },
  },
];

const sortMovies = (data, getValueByProp) => {
  data.sort((a, b) => 
  {
    const v1 = getValueByProp(a);
    const v2 = getValueByProp(b);
    return v1.localeCompare(v2);
  });
}
sortMovies(movies, (item) => item.title);
console.log(movies);

sortMovies(movies, (item) => item.genre.name);
console.log(movies);

Upvotes: 1

Bala.Raj
Bala.Raj

Reputation: 1051

just change it like this

const sortMovies = (item) => {
       return movies.sort((a, b) =>
          a[item]> b[item]? 1 : b[item]> a[item]? -1 : 0
        );
      };
    
const sortTitle = sortMovies("title");

For more nested: I don't recommend this because of performance issue. Just to show the possibility

function getPropByString(obj, propString) {
    if (!propString)
        return obj;

    var prop, props = propString.split('.');

    for (var i = 0, iLen = props.length - 1; i < iLen; i++) {
        prop = props[i];

        var candidate = obj[prop];
        if (candidate !== undefined) {
            obj = candidate;
        } else {
            break;
        }
    }
    return obj[props[i]];
}
const sortMovies = (item) => {
    return movies.sort((a, b) =>
      getPropByString(a,item) > getPropByString(b,item)? 1 : getPropByString(b,item) > getPropByString(a,item) ? -1 : 0
    );
  };

  const sortTitle = sortMovies("title");
  const sortGenre = sortMovies("genre.name");

Upvotes: 1

Azad
Azad

Reputation: 5264

the following code snippet may help you

const movies = [
  {
    title: "Terminator",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Die Hard",
    genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
  },
  {
    title: "Get Out",
    genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
  },
];


//sort by title
var sortedByTitle = movies.sort( (a, b) => {

if(a.title < b.title) { return -1; }
    if(a.title > b.title) { return 1; }
    return 0;

} );

console.log(sortedByTitle);

//sort by genre
var sortedGenre = movies.sort( (a, b) => {

if(a.genre.name < b.genre.name) { return -1; }
    if(a.genre.name > b.genre.name) { return 1; }
    return 0;

} );

console.log(sortedGenre);

Upvotes: 1

Related Questions