0

I have an array of objects, from which I want to filter distinct movie titles and create another array of objects.

    var movs = [
        {
            "Id": 3446,
            "FilmId": "ST00000358",
            "FilmPackageId": null,
            "Title": "Harry Potter and the Goblet of Fire",
        },
        {
            "Id": 3447,
            "FilmId": "ST00000358",
            "FilmPackageId": null,
            "Title": "Harry Potter and the Goblet of Fire",
        },
        {
            "Id": 3448,
            "FilmId": "ST00000359",
            "FilmPackageId": null,
            "Title": "Harry Potter and the Order of the Phoenix",
        },
        {
            "Id": 3449,
            "FilmId": "ST00000360",
            "FilmPackageId": null,
            "Title": "Spider-Man: Into The Spider-Verse",
        },
        {
            "Id": 3450,
            "FilmId": "ST00000360",
            "FilmPackageId": null,
            "Title": "Spider-Man: Into The Spider-Verse",
        }
    ]

I want to create an array of objects, which filter down to the distinct movie title and its id.


    [
        {
            Title: 'Harry Potter and the Goblet of Fire',
            FilmId: 'ST00000358'
        },
        {
            Title: 'Harry Potter and the Order of the Phoenix',
            FilmId: 'ST00000359'
        },
        {
            Title: 'Spider-Man: Into The Spider-Verse',
            FilmId: 'ST00000360'
        }
    ]

I have successfully got an array of distinct titles, with the below, but if i add additional fields to the map, it returns the whole array, not the distinct few.


    const movies = [...new Set(movs.map(item => item.Title))];

this does not work:

const movies = [
    ...new Set(
      movs.map((obj) => ({ label: obj.Title, value: obj.FilmId }))
    )
  ];
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • 1
    JavaScript doesn't compare objects based on the contents. `{a: 1} !== {a: 1}` – Barmar Aug 13 '20 at 23:09
  • 1
    Reduce could help. – Nikolaus Aug 13 '20 at 23:11
  • You could map + Set an array of FilmId, and from that resulting list map an array of a single element found using each FilmId – Taplar Aug 13 '20 at 23:12
  • Does this answer your question? [Create array of unique objects by property](https://stackoverflow.com/questions/18773778/create-array-of-unique-objects-by-property) – ggorlen Aug 13 '20 at 23:14

3 Answers3

2

This is caused by how JS compares Objects and Strings (strings by value, object by reference), so

{k:1} === {k:1} === false

in order to get this kind of set you can use something like reduce:

var movs = [
   {
       "Id": 3446,
       "FilmId": "ST00000358",
       "FilmPackageId": null,
       "Title": "Harry Potter and the Goblet of Fire",
   },
   {
       "Id": 3447,
       "FilmId": "ST00000358",
       "FilmPackageId": null,
       "Title": "Harry Potter and the Goblet of Fire",
   },
   {
       "Id": 3448,
       "FilmId": "ST00000359",
       "FilmPackageId": null,
       "Title": "Harry Potter and the Order of the Phoenix",
   },
   {
       "Id": 3449,
       "FilmId": "ST00000360",
       "FilmPackageId": null,
       "Title": "Spider-Man: Into The Spider-Verse",
   },
   {
       "Id": 3450,
       "FilmId": "ST00000360",
       "FilmPackageId": null,
       "Title": "Spider-Man: Into The Spider-Verse",
   }
]

console.log(Object.values(movs.reduce((acc, {FilmId, Title}) => (acc[FilmId] = {Title, FilmId}, acc), {})));
Alberto Sinigaglia
  • 12,097
  • 2
  • 20
  • 48
1

You can filter based on a specific key using a Set and then use map.

var movs = [{ "Id": 3446, "FilmId": "ST00000358", "FilmPackageId": null, "Title": "Harry Potter and the Goblet of Fire", }, { "Id": 3447, "FilmId": "ST00000358", "FilmPackageId": null, "Title": "Harry Potter and the Goblet of Fire", }, { "Id": 3448, "FilmId": "ST00000359", "FilmPackageId": null, "Title": "Harry Potter and the Order of the Phoenix", }, { "Id": 3449, "FilmId": "ST00000360", "FilmPackageId": null, "Title": "Spider-Man: Into The Spider-Verse", }, { "Id": 3450, "FilmId": "ST00000360", "FilmPackageId": null, "Title": "Spider-Man: Into The Spider-Verse", } ];
let set = new Set();
const res = movs.filter(({FilmId})=>!set.has(FilmId) && set.add(FilmId)).map(({Title,FilmId})=>({Title,FilmId}));
console.log(res);
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
0

You could even use forEach to do the job:

var movs = [{ "Id": 3446, "FilmId": "ST00000358", "FilmPackageId": null, "Title": "Harry Potter and the Goblet of Fire", }, { "Id": 3447, "FilmId": "ST00000358", "FilmPackageId": null, "Title": "Harry Potter and the Goblet of Fire", }, { "Id": 3448, "FilmId": "ST00000359", "FilmPackageId": null, "Title": "Harry Potter and the Order of the Phoenix", }, { "Id": 3449, "FilmId": "ST00000360", "FilmPackageId": null, "Title": "Spider-Man: Into The Spider-Verse", }, { "Id": 3450, "FilmId": "ST00000360", "FilmPackageId": null, "Title": "Spider-Man: Into The Spider-Verse", } ];

let sortedArray = [];
movs.forEach(({Title, FilmId}) => {return sortedArray[FilmId] = {Title, FilmId}});

console.log(Object.values(sortedArray));
Jakub A Suplicki
  • 4,586
  • 1
  • 23
  • 31