JSHowTo
JSHowTo

Reputation: 118

Find completely unique names in an array

Given an array of full names, where each name is in the format 'lastName, firstName', I want to find the completely unique names, i.e. given the names array below

const names = [
    'Smith, Joan',
    'Smith, John',
    'Smith, Sam',
    'Thomas, Joan',
    'Upton, Joan',
    'Upton, Tom',
    'Vasquez, Cesar'
  ]
- Smith, John     # Already saw a last name "Smith"
- Smith, Sam      # Already saw a last name "Smith"
- Thomas, Joan    # Already saw a first name "Joan"
- Upton, Joan     # Already saw a first name "Joan"
- Upton, Tom      # Already saw a last name "Upton"

I want to have as a result only

 Smith, Joan
 Vasquez, Cesar

This is the function I have so far. However, I'd like to rewrite it to avoid the nested for loops and improve performance.

function findUnique() {
  const names = [
    'Smith, Joan',
    'Smith, John',
    'Smith, Sam',
    'Thomas, Joan',
    'Upton, Joan',
    'Upton, Tom',
    'Vasquez, Cesar'
  ];

  let result = names;
  for (var i = 0; i < names.length; i++) {
    for (var j = 1; j < names.length; j++) {
      let names1 = names[i].split(', ');
      let names2 = names[j].split(', ');
      if (names1[0] == names2[0] || names1[0] == names2[1] || names1[1] == names2[0] || names1[1] == names2[1]) {
        result.splice(i, 1);
      }
    }
  }

  return result;
}

Upvotes: 1

Views: 1270

Answers (4)

Bakudan
Bakudan

Reputation: 19482

A solution using filter and single Set. Resulted array is directly returned. An element is added only if true is returned from the callback.

const names = [
    'Smith, Joan',
    'Smith, John',
    'Smith, Sam',
    'Thomas, Joan',
    'Upton, Joan',
    'Upton, Tom',
    'Vasquez, Cesar'
];

var n = new Set();

var unique = names.filter(function(name) {
    var np = name.split(", ");
    if (n.has(np[0]) || n.has(np[1])) {
        return false;
    }
    n.add(np[0]).add(np[1]);
    return true;
});

Upvotes: 0

Leftium
Leftium

Reputation: 17903

Remember what names we have seen using JavaScript object hashes. Then we can run through the array just a single time:

function findUnique() {
  const names = [
    'Smith, Joan',
    'Smith, John',
    'Smith, Sam',
    'Thomas, Joan',
    'Upton, Joan',
    'Upton, Tom',
    'Vasquez, Cesar'
  ];
  
  firstNames = {}; // First names we have already seen.
  lastNames = {};  // Last names we have already seen.
  result = [];
  
  for (var i = 0; i < names.length; i++) {
    let splitName = names[i].split(', ');
    let firstName = splitName[0];
    let lastName = splitName[1];
    
    // Check if we have seen either first name or last name.
    if (!(firstNames[firstName] || lastNames[lastName])) {
      // This is a "unique" name.
      result.push(names[i]);
    }
    
    // Add names to lists of names we have seen.
    firstNames[firstName] = true;
    lastNames[lastName] = true;
  }
   
  return result;
}

console.log(findUnique());

Upvotes: 0

thedayturns
thedayturns

Reputation: 10823

This is how I would write it:

const names = [
  'Smith, Joan',
  'Smith, John',
  'Smith, Sam',
  'Thomas, Joan',
  'Upton, Joan',
  'Upton, Tom',
  'Vasquez, Cesar'
];

const namesSeen = {};
const uniqueNames = [];

for (const name of names) {
  const [last, first] = name.split(", ");

  if (!namesSeen[first] && !namesSeen[last]) {
    uniqueNames.push(name);
  }

  namesSeen[first] = true;
  namesSeen[last] = true;
}

console.log(uniqueNames);

I noticed that you were using const, so I used a few other ES6 features to make the code feel more natural: destructuring and for...of loops.

Upvotes: 1

zfrisch
zfrisch

Reputation: 8660

Use the Set object. It is specifically designed so that only one of each value can be put inside of it. It has the methods .has(value) and .add(value)

I also use the for...of loop to take care of iterating through the list.

Demo: https://jsfiddle.net/6tq00maq/1/

 const names = [
  'Smith, Joan',
  'Smith, John',
  'Smith, Sam',
  'Thomas, Joan',
  'Upton, Joan',
  'Upton, Tom',
  'Vasquez, Cesar'
]

//set up lists for first and last names
var firstNameList = new Set();
var lastNameList = new Set();

//set place for unique names to be stored
var uniqueNames = [];

//iterate list
for (var name of names) {
  var firstName = name.split(", ")[1];
  var lastName = name.split(", ")[0];

  //check if first name or last name are already indexed
  if (!firstNameList.has(firstName) && !lastNameList.has(lastName)) {
  //if not, push them to the unique names to return
    uniqueNames.push(lastName + ", " + firstName);
  }
  //add to indexed names
  firstNameList.add(firstName);
  lastNameList.add(lastName);
}
console.log(uniqueNames);

Upvotes: 3

Related Questions