0

I'm using the code below to add element to the array conditionally: when for a domain in arr1 there isn't a kwd in arr2 for that domain then add the keys: domain, key, position: "n/a", date, engine and device.

jsfiddle

var arr1 = ["xxx", "yyy"];

var arr2 = [
  { domain: "xxx", kwd: "a", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},
  { domain: "yyy", kwd: "a", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "xxx", kwd: "b", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},
  { domain: "yyy", kwd: "b", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "yyy", kwd: "c", position: 2, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"},

  { domain: "xxx", kwd: "d", position: 1, date: "2021-05-07T08:05:16.806Z", engine: "google", device: "desktop"}
];

const grouped = arr2.reduce((group, entry) => {
  const lookup = group[entry.kwd] || {};
  return {
    ...group,
    [entry.kwd]: {
      ...lookup,
      [entry.domain]: entry
    }
  };
}, {});

const filledIn = Object.entries(grouped).reduce(
  (arr, [key, group]) => [
    ...arr,
    ...arr1.map((domain) =>
      domain in group
        ? group[domain]
        : {
            domain,
            kwd: key,
            position: "n/a",
            date: grouped.date,
            engine: grouped.engine,
            device:grouped.device,
          }
    )
  ],
  []
);

console.log(filledIn);

The script works fine but return undefined date, engine and device.

...
{
  date: undefined,
  device: undefined,
  domain: "yyy",
  engine: undefined,
  kwd: "d",
  position: "n/a"
}]

How can I fix this?

Thanks

3
  • Running your jsfiddle shows that only some of the entries don't have date and engine. Have you tried debugging your code? Commented May 7, 2021 at 15:08
  • Your missing the objects for kwd: d and domain: yyy when you define arr2 likewise for kwd: c and domain: xxx Commented May 7, 2021 at 15:09
  • Is your goal to return "n/a" instead of undefined? Commented May 7, 2021 at 15:47

2 Answers 2

4

Here's the code modified to fill in more values on a missing domain from my original answer. I also added some comments.

Edit: I was able to make the code even simpler by using flatMap() in the last step instead of manually producing a flat array with reduce().

// Group all array rows by their keyword, and inside of the group index each
// entry by its domain, so we can easily check if a domain is in this group.
// Also store an an example of a known good entry so we can clone its values
// onto missing entries in the next step
const grouped = arr2.reduce(
  (groups, entry) => ({
    ...groups,
    [entry.kwd]: {
      ...(groups[entry.kwd] || {}),
      example: entry,
      [entry.domain]: entry
    }
  }),
  {}
);

// Now iterate over the group and pull out all the valid known domains and put
// it back into array form. If a domain is missing, use the "example" we
// captured get example values of a valid domain, and fill in the rest manually
const filledIn = Object.values(grouped).flatMap((group) =>
  arr1.map(
    (domain) =>
      group[domain] || {
        ...group.example,
        position: "n/a"
      }
  )
);

console.log(filledIn);
Sign up to request clarification or add additional context in comments.

Comments

1

I've done what you were doing but with simpler code. See if it's what you wanted.

In the example, the final log has grouped the same lettered objects together, you can change that by using ...

const arr1 = ["xxx", "yyy"];

const arr2 = [{
    domain: "xxx",
    kwd: "a",
    position: 1,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  },
  {
    domain: "yyy",
    kwd: "a",
    position: 2,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  },

  {
    domain: "xxx",
    kwd: "b",
    position: 1,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  },
  {
    domain: "yyy",
    kwd: "b",
    position: 2,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  },

  {
    domain: "yyy",
    kwd: "c",
    position: 2,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  },

  {
    domain: "xxx",
    kwd: "d",
    position: 1,
    date: "2021-05-07T08:05:16.806Z",
    engine: "google",
    device: "desktop"
  }
];

// making a new array with all the kwd options.
// use Set() for unique items in array, so no duplicates.
const letters = [...new Set(arr2.map(elm => elm.kwd))];

// looping through letters
const filled = letters.map(letter => {

  // looping through domains
  return arr1.map((domain, i) => {

    // if the domain and letter combination already exists, make a copy of the object and return it.
    if (arr2.some(obj => obj.domain == domain && obj.kwd == letter)) {
      const copy = arr2.find((elm) => elm.kwd === letter && elm.domain === domain);
      return Object.assign({}, copy);
    }

    // if there are no copies, copy the other domain with the same letter and change the domain and position.
    let copy = arr2.find(({
      kwd
    }) => kwd === letter);
    copy.domain = domain;
    copy.position = i + 1;
    return Object.assign({}, copy);
  });
});


console.log(filled);

2 Comments

When I approach problems like these, I think about parsing a useful intermediary format if it will help the problem. Doing an initial grouping lets me do simple in check to verify if a value is present. Without that, you have to work with the limitations of the initial data structure, aka here using .some()and .find() twice with search logic you have to write. The efficiency of these nested loops probably doesn't matter for such a small data set. Mixing the parsing and problem solving as you've done here works, for me personally it's easier to reason about separate steps
Yep, many nested loops can be very slow, especially map and forEach, I just used them because it's a lot easier to see what's happening to the data. Your version would be better for production but hard for new programmers to follow.

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.