Creating a unique array of objects in ES6 using a `Set` to

I recently discovered this interesting method for creating unique arrays using ES6:

[ ...new Set(array) ]

It worked well for me until I attempted to use it with an array of objects, and unfortunately, it did not return a unique array as expected.

For example:

let items = [ ...new Set([{id:123, value:'test'}, {id:123, value:'test'}]) ];

Can anyone explain why this is happening?

Answer №1

If you want to create a unique array, you can use the following function:

uniqueArray = a => [...new Set(a.map(o => JSON.stringify(o)))].map(s => JSON.parse(s))

Although it may not be the prettiest solution, it usually works well. However, be aware that if your object parameter contains a new Date(), it will be converted to an ISO string during the stringify process.

For example, you can use the function like this:

let arr = [{id:1},{id:1},{id:2}];
uniqueArray(arr) //[{id:1},{id:2}]

Answer №2

What is the reason for this?

According to the official documentation

The Set object allows you to store distinct values of various types, whether they are primitive values or object references.

Each reference to those arrays within the Set constructor will have a unique identity, thus making them not classified as a single value by the constructor.

Answer №3

This code snippet demonstrates a method that will work:

let reference = {id:123, value:'test'}
let array = [...new Set([reference, reference])]

>> [{id:123, value:'test'}]

Here is an explanation of what you're actually doing in the code:

let ref1 = {id:123,value:'test'} // creates a reference to a memory location
let ref2 = {id:123,value:'test'} // establishes a new reference to a different memory location

let array = [...new Set([ref1, ref2])]

>> [{id:123,value:'test'},{id:123,value:'test'}]

Answer №4

If you choose not to utilize a library such as lodash or radash, there is an alternative solution using Set as suggested by @Vic. A bug arises when dealing with objects that do not have the same key order. For instance, {a: '1', b: '2'} and {b: '2', a: '1'} are not considered equal strings. Below is a functional implementation that covers these cases:

Implementation

uniq(source) {
  if (!Array.isArray(source)) {
     return [];
  }
  return [...new Set(source.map(o => {
    const sortedObjectKeys = Object.keys(o).sort();
    const obj = Object.assign({}, ...sortedObjectKeys.map(k => ({[k]: o[k]})) as any);
    return JSON.stringify(obj);
  }))]
  .map(s => JSON.parse(s));
}

Test cases

describe(`uniq`, () => {
  it('should return unique collection values', () => {
    expect(uniq([{v: 1}, {v: 2}, {v: 1}])).toEqual([{v: 1}, {v: 2}]);
  });

 it('should return unique collection values for unsorted properties', () => {
   expect(uniq([{a: 'test', v: 1}, {v: 2}, {v: 1, a: 'test'}])).toEqual([{a: 'test', v: 1}, {v: 2}]);
 });

 it('should return empty array for non array source', () => {
   expect(uniq({v: 1})).toEqual([]);
   expect(uniq('aString')).toEqual([]);
   expect(uniq(125)).toEqual([]);
   expect(uniq(true)).toEqual([]);
   expect(uniq([])).toEqual([]);
   expect(uniq(undefined)).toEqual([]);
   expect(uniq(null)).toEqual([]);
});

});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the solution to having a div move along with window resizing without displacing adjacent divs?

After much effort, I still can't seem to get this working correctly. I've been playing around with a section named "RightExtra" and a div inside it called "RightExtraContent". My goal is to allow these two divs to move freely when the window is ...

Utilize Ajax and Nodejs to inject dynamic content into your webpage

Seeking assistance in implementing a project where a navigation bar on the page contains various items, and I aim to display the content of each tab without reloading the entire page. Utilizing Nodejs with the ejs template engine, my research hasn't l ...

Is there a way for me to obtain the present value of the chosen button in the list below?

I am working with a group of three buttons labeled English, Hindi, and Urdu. How can I retrieve the value of the selected button in a JavaScript function? <div class="btn-group" data-toggle="buttons"> <label class="btn btn-primary active"> ...

Sequentially iterate through elements based on their Data attributes

Assume you are working with HTML elements like the ones shown below <span class="active" data-id="3"> Test 3 </span> <span class="active" data-id="1"> Test 1 </span> <span class="activ ...

Revamping jQuery for a React component

As I transition away from using jQuery for quick hides, shows, and CSS changes in favor of React components that require re-rendering without triggering the jQuery actions requiring a page refresh, I find myself needing to set state within each component. ...

Multiple ngFor loops causing only the final item to be displayed in the inner loop

Can someone assist with my code where I loop through firebase RTDB reference to retrieve a list and then use those results in a subsequent firestore query? The console logs the correct data, but my code only displays the last item in the loop inside ngFor. ...

Adding a badge to a div in Angular 6: What you need to know!

How can I add a badge to a specific div in Angular 6? I have dynamic div elements in my HTML. I want to increase the counter for a specific div only, rather than increasing it for all divs at once. For example, I have five divs with IDs div1, div2, div3, ...

Tap on the image to enlarge

I have a question regarding using thumbnails from Bootstrap. I am trying to create functionality where when I click on a thumbnail, the picture with its original sizes appears and then disappears when clicked anywhere else on the page. Below is an exampl ...

Unable to hide jQuery form and receiving undefined function output

I seem to be facing an issue with one of the buttons. It's not functioning properly. Whenever I click on the "Add Run" button followed by the "Home" button, most functions stop working as expected. The dynamically created form doesn't hide, the ...

The current version of HTML5 Context Menus is now available

I'm in need of implementing the HTML5 Context Menu feature. Currently, only Firefox supports it. My main objective is to add some menu options without replacing the existing context menu. How can I achieve the same functionality now? I am aware of va ...

Something is seriously wrong with the datetime in fullcalendar JavaScript

I've been diving into a tutorial for creating a calendar scheduler in asp.net MVC5 from this link. One issue I'm facing is the datetime being passed and stored as the min value in the database (1/1/0001 12:00:00 AM), almost like it's null b ...

Trouble obtaining AJAX result using onClick event

As a newbie to AJAX, I am still trying to grasp the concept. My task involves using an AJAX call to extract specified information from an XML file. Even after carefully parsing all tag elements into my JavaScript code, I encounter a problem when attempting ...

Repeated information displayed in modal pop-ups

HTML <a class="btn" data-popup-open="popup-1" href="#">More Details</a> <div class="popup" data-popup="popup-1"> <div class="popup-inner"> <h2>Unbelievable! Check this Out! (Popup #1)</h2> ...

Updating an AngularJS directive with a change in URL: Best practices

Similar Question: Customizing tab styles in AngularJS Utilizing AngularJS, I am attempting to include a "current" class in my menu item whenever the content of that tab is being shown. The current implementation works as expected upon page load: HTML ...

What are the steps to create a project template in WebStorm by saving an existing project?

Currently, I am working on my Express.js project in WebStorm 8 and I would like to save it as a project template. Can you please guide me on how to do this using WebStorm? ...

From Android JSON array to a list of items

In my android app, I have encountered an issue while trying to parse a JSONArray into an ArrayList. The PHP script returns the expected results correctly, but when attempting to add the results to the ArrayList in Java, a null pointer exception occurs at ...

What could be causing the discrepancy in the first and second socket request in my Node.js code?

Below is my echo server code snippet var net = require('net') var server = net.createServer(function(socket) { socket.write('Echo server\r\n'); socket.on(&ap ...

What is Angular's approach to managing the @ symbol in view paths?

I found some interesting data lake sources on AWS. I came across their package.js file, which includes the following code: '@package': { templateUrl: 'package/package.html', controller: 'PackageCtrl' } I am curious a ...

Searching for a specific string within a two-dimensional array using Java

Currently, I am attempting to locate a specific string within a char[][] array. The issue I am encountering with my code is that when charArray[k] matches, it also needs to match puzzle[i][j+1] and continue matching for the entire length of charArray. Th ...

Issue with React router not functioning correctly when dealing with dynamically created anchor tags utilizing jquery

As a newcomer to React.js, I have incorporated jQuery into my project to handle mouse and click events for cloning navigation elements, specifically <li> tags within <a> tags. The cloned elements are displayed in a targeted div ID successfully. ...