3
\$\begingroup\$

The following is some JavaScript that I wrote to join two arrays of objects by an identifier. The goal is to extend the objects in a1 to include the extra fields in a2 and a3. What could I improve here? One question I have is, should I refactor this so the objects in a1 aren't modified in-place with Object.assign, instead having a new Object getting created so it follows a functional style?

function groupBy(keyExtract, arr) {
  return arr.reduce((result, item) => {
    const key = keyExtract(item);
    if (result.has(key)) {
      result.set(key, [...result.get(key), item]);
    } else {
      result.set(key, [item]);
    }

    return result;
  }, new Map());
}

function merge(groups, array, mergeKey) {
  array.forEach(it => {
    try {
      const group = groups.get(it[mergeKey]);
      if (!group) {
        throw `${mergeKey} ${it[mergeKey]} not found`;
      }
      group.map(item => {
        return Object.assign(item, it);
      });
    } catch (e) {
      console.log(it, `Error merging record with ${mergeKey}: ${it[mergeKey]}`, e);
    }
  });
}

function flatten(groups, arrayMap) {
    let arr = []
    for (const [index, group] of groups.entries()) {
      arr.push(...group);
    }
  return arr;
}

// usage example
const a1 = [{ssid: 123, score: 100, test_id: 456}, {ssid: 123, score: 50, test_id: 789}];
const a2 = [{ssid: 123, student_number: 321}];
const a3 = [{test_name: 'test', test_id: 456}, {test_name: 'test2', test_id: 789}];

const ssid_groups = groupBy(item => item.ssid, a1);
const test_id_groups = groupBy(item => item.test_id, a1);

merge(ssid_groups, a2, 'ssid');
merge(test_id_groups, a3, 'test_id');

const results = flatten(ssid_groups);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.