1

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!

4
  • change a.item to a[item] - likewise for b Commented Feb 2, 2021 at 5:53
  • Do you want to sort them with both of those properties OR do you want to create a generic function pass different parameters as a string? Commented Feb 2, 2021 at 5:59
  • @adiga I think the OP wants to sort title then genre.name. Otherwise, the result looks weird :) Commented Feb 2, 2021 at 6:01
  • @adiga hi, I want to create 2 new arrays, one is sorted by title and the other one is sorted by genre.name. Sorry for the confusion. Commented Feb 2, 2021 at 6:05

4 Answers 4

1

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);

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for your input. I want to create 2 new arrays, one is sorted by title and the other one is sorted by genre.name. Sorry for the confusion. May I ask in which situation I should use your code? It looks interesting. I appreciate it!
@adiga I've just updated my answer with generic method, Pls, take a look at it, sir :)
Awesome! I think it does after running code snippet. Thank you so much!! By the way, how should I use React's onClick to run this function please? Since we can't do this: onClick = sortMovies(movies, (item) => item.title) as I understand.
Regarding your new issue related to React's onClick, you should give us more of your sample code or create a new question? then tag me I'll help you. Because we should not make this question too complex
1

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);

3 Comments

No, The OP wants to create a generic method instead.
@Phong Yes, the real objects I'm working on have many keys. Here I simplified it to only 2.
@Tui do you need a function which sort by given property name? some thing like sortMovies("title") or sortMovies("genre/name")
1

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");

2 Comments

Thanks, Bala! I tried the first part, but it was undefined after I ran console.log(sortTitle)?
oh my bad! "return" keyword
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.