JS - How can i compare two item in an array with nearly similar string

Viewed 69

Example 1: I have an array like this

let arrayA = ["task A - memberA", "task A - memberB", "task B - memberA"]

I want to find out if two members doing the same task, then remove the task from the after one. The expected output of Example 1 should be:

arrayA = ["task A - memberA", "task B - memberA"]

Example 2:

let arrayA = [{task: "Task A", member: "MemberA"},{task: "Task A", member: "MemberB"},{task: "Task B", member: "MemberB"}]

Expected result 2:

arrayA = [{task: "Task A", member: "MemberA"},{task: "Task B", member: "MemberB"}]

Thank you,

5 Answers

Create a Set that keeps track of active tasks.

Then loop over the tasks array and extract the task by splitting the string and then if the task is not present in the Set then push it to the resultant array.

let tasks = ["task A - memberA", "task A - memberB", "task B - memberA"];

function getUniqueTasks(tasks) {
  const activeTasks = new Set();
  const uniqueTasks = [];
  tasks.forEach((t) => {
    const [task] = t.split(" - ");
    if (!activeTasks.has(task)) {
      uniqueTasks.push(t);
      activeTasks.add(task);
    }
  });
  return uniqueTasks;
}

console.log(getUniqueTasks(tasks));

If you're looking for a fancy one liner, then refer to the solution below:

const 
  data = ["task A - memberA", "task A - memberB", "task B - memberA"],
  filterer = (s) => (d, _i, _a, t = d.split(" - ")[0]) => !s.has(t) && s.add(t),
  result = data.filter(filterer(new Set()));

console.log(result);

Relevant documentations:

by using reduce method,

  • get substring before '-' i.e task name
  • check whether task name exist in pv or not
  • if pv (previousValue) array of reduce function, doesn't contain the task then add that new task into it.

hint:
some method returns true or false
includes method return true or false
substr method return sub string from string i.e task name
refer MDN tutorials for more details

let arr = ["task A - memberA", "task A - memberB", "task B - memberA"]

let result = arr.reduce((pv,cv) => {
  if(!pv.some(e => e.includes(cv.substr(0, cv.indexOf('-')).trim()))) pv.push(cv)
  return pv
},[])

console.log(result)

for second example just replace
if(!pv.some(e => e.task.includes(cv.task.trim()))) pv.push(cv)

You could take a Set and a function for wanted unique part of the string.

const
    getTask = s => s.split(' - ', 1)[0],
    uniqueBy = fn => s => v => (w => !s.has(w) && s.add(w))(fn(v)),
    data = ["task A - memberA", "task A - memberB", "task B - memberA"],
    result = data.filter(uniqueBy(getTask)(new Set));
    
console.log(result);

For example:

const arrayA = ["task A - memberA", "task A - memberB", "task B - memberA"];

function removeDuplicateTasks(tasksArray) {

    // Use set as a temporary data structure to "remember" tasks names
    const tasks = new Set();

    // Arrays have .filter() method that iterates over elements of the
    // array and uses callback function to "decide" whether given
    // element should be filtered out. Returning true from the callback
    // tells the .filter() method to let that element pass through.
    let filteredTasks = tasksArray.filter(function (task, taskIndex, tasksArr) {
        const taskName = task.split('-')[0].trim();
        if (!tasks.has(taskName)) {
            // This task name was not yet used
            tasks.add(taskName);
            // So do not throw it away but let it pass through to filteredTasks array
            return true;
        }
    });

    return filteredTasks;

}

const cleanedArrayA = removeDuplicateTasks(arrayA);

If I were you I'd consider using different data structure to represent member - tasks relationship.

You can use a combination of map, filter and findIndex to get only the first entries for each specific task.

First, use map to transform the array in something that's a little easier to work with, an array of [task, member] entries.

Then, filter that array, so only those items are returned that are at the first position where you can find their specific task.

let arrayA = ["task A - memberA", "task A - memberB", "task B - memberA"];

const assignments = arrayA.map(t => t.split(' - '));
const filtered = assignments.filter(
  ([task], i) => assignments.findIndex(
    ([t]) => t === task) === i);

console.log(filtered);

As for example 2, you use the exact same approach, aside from some variable names that changed, and you don't need to split any more:

let arrayA = [{task: "Task A", member: "MemberA"},{task: "Task A", member: "MemberB"},{task: "Task B", member: "MemberB"}];

const filtered = arrayA.filter(
  ({task}, i) => arrayA.findIndex(
    (assignment) => assignment.task === task) === i);

console.log(filtered);

Related