0

A little background: was asked to answer the question on a technical interview, couldn't, and now I want to improve but can't find the logic to answer.

## CASE 1 ##

Given Input:

const profiles = ["Bill", "Steve", "Zuck"]
const skills = 
        [["Digital Marketing","SEO","UI/UX"], 
        ["Accounting","Digital Marketing","Employer Branding"], 
        ["Accounting","UI/UX"]]


Expected Output:

    [[["Accounting"],["Steve","Zuck"]], 
    [["Digital Marketing"],["Bill","Steve"]], 
    [["Employer Branding"],["Steve"]], 
    [["SEO"],["Bill"]], 
    [["UI/UX"],["Bill","Zuck"]]]
## CASE 2 ##

Given Input:

const profiles= ["First", "Fourth", "Second", "Third"]

const skills =
        [["One","Three","Two"], 
        ["One","One three","One two"], 
        ["One two","One two three","Two"], 
        ["One","One three","One two","One two three","Three","Two"]]

Expected Output:
    [[["One"],["First","Fourth","Third"]], 
    [["One three"],["Fourth","Third"]], 
    [["One two"],["Fourth","Second","Third"]], 
    [["One two three"],["Second","Third"]], 
    [["Three"],["First","Third"]], 
    [["Two"],["First","Second","Third"]]]

Thank you very much!

6
  • 3
    How did you decide that Steve and Zuck are in Accounting? Commented Jul 2, 2020 at 17:14
  • 1
    did they give any pattern to follow? finding it difficult to understand the relation. Commented Jul 2, 2020 at 17:15
  • 1
    @GhassenLouhaichi There is a 1-to-1 correspondence between the two input arrays. Bill is in Digital Marketing, SEO, and UI/UX, Steve is in Accounting, Digital Marketing, and Branding, etc. Commented Jul 2, 2020 at 17:17
  • @JLRishe I see it now, that was illusive, impressive of you! Commented Jul 2, 2020 at 17:18
  • @Muhamad Hafiz can you show us what you tried so far? Commented Jul 2, 2020 at 17:20

4 Answers 4

1

There may be a more elegant way to do this, but it seems to do the trick.

Comments in the code to explain what it's doing.

function addSkills(skillGroups, profile, skills) {
  for (let skill of skills) {
    // add profile to the array for the current skill, or add a new
    // entry if this is the first time we're encountering it
    skillGroups[skill] = [
        ...(skillGroups[skill] || []),
        profile
    ];
  }
}

function groupSkills(profiles, skills) {
  // mapping from skill name to the profiles in that skill
  let skillGroups = {};

  for (let i = 0; i < profiles.length; i += 1) {
    addSkills(skillGroups, profiles[i], skills[i]);
  }

  const entries = Object.entries(skillGroups);

  // sort by skill name
  entries.sort(([l], [r]) => l.localeCompare(r));

  // place the skill names in an array and return
  return entries.map(([skill, profiles]) => [
    [skill], profiles
  ]);
}

chai.expect(groupSkills(
  ["Bill", "Steve", "Zuck"], [
    ["Digital Marketing", "SEO", "UI/UX"],
    ["Accounting", "Digital Marketing", "Employer Branding"],
    ["Accounting", "UI/UX"]
  ]
)).to.deep.equal([
  [
    ["Accounting"],
    ["Steve", "Zuck"]
  ],
  [
    ["Digital Marketing"],
    ["Bill", "Steve"]
  ],
  [
    ["Employer Branding"],
    ["Steve"]
  ],
  [
    ["SEO"],
    ["Bill"]
  ],
  [
    ["UI/UX"],
    ["Bill", "Zuck"]
  ]
]);

chai.expect(groupSkills(
  ["First", "Fourth", "Second", "Third"], [
    ["One", "Three", "Two"],
    ["One", "One three", "One two"],
    ["One two", "One two three", "Two"],
    ["One", "One three", "One two", "One two three", "Three", "Two"]
  ]
)).to.deep.equal([
  [
    ["One"],
    ["First", "Fourth", "Third"]
  ],
  [
    ["One three"],
    ["Fourth", "Third"]
  ],
  [
    ["One two"],
    ["Fourth", "Second", "Third"]
  ],
  [
    ["One two three"],
    ["Second", "Third"]
  ],
  [
    ["Three"],
    ["First", "Third"]
  ],
  [
    ["Two"],
    ["First", "Second", "Third"]
  ]
]);

console.log('all tests passed!');
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>

Sign up to request clarification or add additional context in comments.

Comments

0

Here is an approach that may be a bit expensive but it outputs the expected result.

For your second example, this code still works, you might want to think about renaming the variables to something more generic.

const profiles = ["Bill", "Steve", "Zuck"];
const skills = [
    ["Digital Marketing","SEO","UI/UX"], 
    ["Accounting","Digital Marketing","Employer Branding"], 
    ["Accounting","UI/UX"]
];

// calculate distinct skills set from skills
const distinctSkills = skills.reduce((acc, cur) => (
    acc.concat(cur.filter((v) => (!acc.includes(v))))
), []).sort();

const result = distinctSkills.map((distinctSkill) => {
    const people = [];
    // for each distinct skill, build the right people array
    // based on skills and profiles
    skills.forEach((skillSet, index) => {
        if (skillSet.includes(distinctSkill)) {
            people.push(profiles[index]);
        }
    });
    return [[distinctSkill]].concat([people]);
});

console.log(result);

2 Comments

Correct me if I'm mistaken, but I think this could produce incorrect results if one skill were a substring of another ("Marketing" and "Digital Marketing"). Arrays have an .includes() method, so why not just use that?
Thank you for your insight @GhassenLouhaichi ! While the other answers are great, I found your answer is the one that 'clicked' fastest for me :)
0

You can first collect all the skill names into a Map, keyed by these names, each with an associated, empty, array as value. Then iterate again over that data to push the corresponding names into those arrays. Then get these arrays out of the map and prefix with the skill name wrapped in its own array. Optionally sort by skill.

const profiles = ["Bill", "Steve", "Zuck"];
const skills = [["Digital Marketing","SEO","UI/UX"], ["Accounting","Digital Marketing","Employer Branding"], ["Accounting","UI/UX"]];

let map = new Map(skills.flatMap(row => row.map(s => [s, []])));
skills.forEach((row, i) => row.forEach(s => map.get(s).push(profiles[i])));
let result = Array.from(map.entries(), ([k,v]) => [[k], v])
                  .sort((a, b) => a[0][0].localeCompare(b[0][0]));

console.log(result);

Comments

0

const profiles = ["Bill", "Steve", "Zuck"];
const skills = [
  ["Digital Marketing", "SEO", "UI/UX"],
  ["Accounting", "Digital Marketing", "Employer Branding"],
  ["Accounting", "UI/UX"]
];

const combine = (profiles, skills) => {

  const indexMap = {};
  const output = [];
  let index = 0;

  //create array of skills and track indexes
  skills.forEach(arr => {
    arr.forEach(skill => {
      if (!indexMap[skill]) {
        indexMap[skill] = index.toString();
        output.push([
          [skill],
          []
        ])
        index++;
      }
    })
  })


  //populate secondary arrays using indexmap for reference
  profiles.forEach((profile, index) => {
    skills[index].forEach(skill => {
      let i = indexMap[skill];
      output[i][1].push(profile);
    })
  })


  //sort names incase not alphabetical
  output.forEach(output => {
    output[1].sort((a, b) => a[0] > b[0] ? 1 : -1);
  })


  // //sort skills incase not alphabetical
  return output.sort((a, b) => a[0] > b[0] ? 1 : -1);
}

console.log(combine(profiles, skills))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.