Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript map then filter unique array items

I know how to do both things separately, but I'm sure there must be a way to combine them.

I have an array of categories, which I am extracting from an array of objects:

 this.videoCategories = this.videos.map(v => v.category);

But of course there are duplicates in this array. So now I do

this.uniqueVideoCategories = this.videoCategories.filter((item, index) => {
  return this.videoCategories.indexOf(item) === index;
});

Which works fine, I get an array of the categories without dupes. But I'm trying to learn and dry up the code a bit by stringing them together, and this does not work - yields empty array

  constructor(private videoService: VideoService) {
    this.videos = videoService.getVideos();
    this.videoCategories = this.videos
      .map(v => v.category)
      .filter((item, index) => {
        return this.videoCategories.indexOf(item) === index;
      });
    console.log(this.videoCategories);
  }
like image 401
Steve Avatar asked Aug 01 '19 15:08

Steve


People also ask

Can I use map and filter together JavaScript?

JavaScript's Array#map() and Array#filter() functions are great when used together because they allow you to compose simple functions. For example, here's a basic use case for filter() : filtering out all numbers that are less than 100 from a numeric array. This function works fine on an array of numbers.

Can we use filter after map?

As the filter() method will return the array with the required elements. Now we will apply map() method to perform the specified operations on all elements of the array returned by filter() method.


3 Answers

Inside the filter() you are checking the index inside the array of objects. You can use the third argument of filter() method which will be the newly created array after map()

 constructor(private videoService: VideoService) {
    this.videos = videoService.getVideos();
    this.videoCategories = this.videos
      .map(v => v.category)
      .filter((item, index, arr) => {
        return arr.indexOf(item) === index;
      });
    console.log(this.videoCategories);
  }

Instead of using filter() and indexOf() you can use Set to remove duplicates. This will be the time-complexity O(N)

constructor(private videoService: VideoService) {
    this.videos = videoService.getVideos();
    this.videoCategories = [...new Set(this.videos.map(v => v.category))]
    console.log(this.videoCategories);
  }
like image 57
Maheer Ali Avatar answered Oct 23 '22 08:10

Maheer Ali


Sometimes the solution is choosing the right data structure. ES6 has introduced Set, which only contains unique objects.

Then you just do:

this.videoCategories = new Set(this.videos.map(v => v.category))

The uniqueness will be handled by browser implementation, instead of cluttering your codebase.

like image 2
Tomáš Zato - Reinstate Monica Avatar answered Oct 23 '22 08:10

Tomáš Zato - Reinstate Monica


var videos = [
  { category: 'category1', title: 'Category 1'},
  { category: 'category1', title: 'Category 1'},
  { category: 'category1', title: 'Category 1'},
  { category: 'category2', title: 'Category 2'},
  { category: 'category2', title: 'Category 2'}
];
var categoryVideos =
  videos
    .map(v => v.category)
    .filter((item, index, arr) => arr.indexOf(item) === index);
    
console.log(categoryVideos);

Array.prototype.filter

Syntax

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

Parameters

callback

Function is a predicate, to test each element of the array. Return true to keep the element, false otherwise. It accepts three arguments:

  • element: The current element being processed in the array.
  • index: (Optional) The index of the current element being processed in the array.
  • array: (Optional) The array filter was called upon.
  • thisArg: (Optional) Value to use as this when executing callback.

Return value

A new array with the elements that pass the test. If no elements pass the test, an empty array will be returned.

like image 1
silentw Avatar answered Oct 23 '22 08:10

silentw