1

I have a array of objects as below

const history = [
  {
    name: "Lance",
    baseline: { risk: "112", age: "45", insurance: "Star" },
  },
  {
    name: "Sam",
    baseline: { risk: "9", age: "21", insurance: "Sigma" },
  },
  {
    name: "Jill",
    baseline: { risk: "15", age: "21", insurance: "Sigma" },
  },
  {
    name: "Bill",
    baseline: { risk: "15", age: "21", insurance: "Mercy" },
  },
];

Then a second one as below


const current = [
  {
    name: "Lance",
    item: "PS",
    "3-Aug-21": "117",
    "4-Aug-21": "120",
    "5-Aug-21": "112",
  },
  {
    name: "Sam",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },

  {
    name: "Jill",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },
  {
    name: "Bill",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },
];

Can anyone get the output as below.

const filteredData= [
{
  insurance: 'Star',
  details:
  {
    name: "Lance",
    values: [
      { date: "3-Aug-21", riskLevel: "104.4" }, //117/112(112 is the baseline risk for Lance)
      { date: "4-Aug-21", riskLevel: "107.1" }, //120/112(112 is the baseline risk for Lance)
      { date: "5-Aug-21", riskLevel: "100" }, //112/112(112 is the baseline risk for Lance)
    ]
  }},
  {insurance: 'Sigma'
  ,
  details:
  {
    name: "Sam",
    values: [
      { date: "3-Aug-21", riskLevel: "112.6" }, //10.14/9(9 is the baseline risk for Sam)
      { date: "4-Aug-21", riskLevel: "113.3" }, //10.2/9(9 is the baseline risk for Sam)
      { date: "5-Aug-21", riskLevel: "111.1" }, //10/9(9 is the baseline risk for Sam)
    ],
name: "Jill",
    values: [
      { date: "3-Aug-21", riskLevel: "112.6" }, //10.14/9(9 is the baseline risk for Sam)
      { date: "4-Aug-21", riskLevel: "113.3" }, //10.2/9(9 is the baseline risk for Sam)
      { date: "5-Aug-21", riskLevel: "111.1" }, //10/9(9 is the baseline risk for Sam)
    ],
  },
},
{insurance: 'Mercy',
details:
  {
    name: "Bill",
    values: [
      { date: "3-Aug-21", riskLevel: "104.4" }, //117/112(112 is the baseline risk for Lance)
      { date: "4-Aug-21", riskLevel: "107.1" }, //120/112(112 is the baseline risk for Lance)
      { date: "5-Aug-21", riskLevel: "100" }, //112/112(112 is the baseline risk for Lance)
    ],
  }
},
];

I got a similar questions answered. Link --> Using an external object in array map() method

The difference in this question is that here I am trying to read the insurance from the history array and then get the values for patients of the same insurance together.

Based on the previous question. I have the Map between name & insurance with the code below.

const historyMap = new Map(history.map(o => [o.name, o.baseline.insurance]));

However, I do not know how to use it further.

I got the code below where they categorize stuff based on the 'coins' (in our case insurance & data is also structured differenly) but I am not able to figure it out.

filteredData = {};
  Object.keys(data).forEach((coin) => {
    filteredData[coin] = data[coin]
      .filter((d) => {
        return !(d["price_usd"] == null);
      })
      .map((d) => {
        d["price_usd"] = Number(d["price_usd"]);
        d["24h_vol"] = Number(d["24h_vol"]);
        d["market_cap"] = Number(d["market_cap"]);
        d["date"] = parseTime(d["date"]);
        return d;
      });
  });
4
  • 1
    In my opinion details in filteredData should be array. Commented Aug 30, 2021 at 8:38
  • If the 'details' is an array, it cannot have name:<value> key/value pair inside it. Commented Aug 30, 2021 at 8:46
  • It will array of object. Using the current format will overwrite the previous value. Commented Aug 30, 2021 at 8:52
  • @moys You mentioned that you are new to JS. But you approved an answer which uses Array.reduce, Array.map, Object destructuring and n number of advanced JavaScript techinques and not a single line explanation provided for the logic that he used. And the best thing is the user stated to Other answes that Assuming the nodes other than name and item in current array as date is not possible since that wont work with dynamic data. The approved answer also uses of the same technique. So what is the reason for the accepting that particular answer? Commented Aug 30, 2021 at 11:40

3 Answers 3

2

You could take a two loops approach with objects as hash tables.

const
    history = [{ name: "Lance", baseline: { risk: "112", age: "45", insurance: "Star" } }, { name: "Sam", baseline: { risk: "9", age: "21", insurance: "Sigma" } }, { name: "Jill", baseline: { risk: "15", age: "21", insurance: "Sigma" } }, { name: "Bill", baseline: { risk: "15", age: "21", insurance: "Mercy" } }],
    current = [{ name: "Lance", item: "PS", "3-Aug-21": "117", "4-Aug-21": "120", "5-Aug-21": "112" }, { name: "Sam", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10" }, { name: "Jill", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10" }, { name: "Bill", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10" }],
    temp = current.reduce((r, { name, item, ...data }) => {
        r[name] = Object
            .entries(data)
            .map(([date, riskLevel]) => ({ date, riskLevel }));
        return r;
    }, {}),
    result = Object.values(history.reduce((r, { name, baseline: { risk, insurance } }) => {
        r[insurance] ??= { insurance, details: [] };
        r[insurance].details.push({
            name,
            values: temp[name].map(({ date, riskLevel }) =>
                ({ date, riskLevel: (100 * riskLevel / risk).toFixed(1) }))
        });
        return r;
    }, {}));
  
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

2

I used reduce() to categorize the insurance and extract the data with Object.values().

note: the precision I didn't know your requirement. I leave for you to adjust. I use toFixed(1) now.

const history = [ { name: "Lance", baseline: { risk: "112", age: "45", insurance: "Star" }, }, { name: "Sam", baseline: { risk: "9", age: "21", insurance: "Sigma" }, }, { name: "Jill", baseline: { risk: "15", age: "21", insurance: "Sigma" }, }, { name: "Bill", baseline: { risk: "15", age: "21", insurance: "Mercy" }, }, ]; 

const current = [ { name: "Lance", item: "PS", "3-Aug-21": "117", "4-Aug-21": "120", "5-Aug-21": "112", }, { name: "Sam", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10", }, { name: "Jill", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10", }, { name: "Bill", item: "PS", "3-Aug-21": "10.14", "4-Aug-21": "10.2", "5-Aug-21": "10", }, ];

const categorizedInsurance = history.reduce((acc, h) => {
  const cur = current.find(c => c.name === h.name);
  const insurance = h.baseline.insurance;
  const keys = Object.keys(cur).filter(key => key !== "name" && key !== "item");
  const values = keys.map(key => ({
    date: key,
    riskLevel: ((cur[key] / h.baseline.risk) * 100).toFixed(1),
  }));

  if (acc[insurance]) {
    acc[insurance].details.push({
      name: h.name,
      values: values,
    });
  } else {
    acc[insurance] = {
      insurance: insurance,
      details: [
        {
          name: h.name,
          values: values,
        },
      ],
    };
  }

  return acc;
}, {});

const output = Object.values(categorizedInsurance);

console.log(output);

7 Comments

it works on the data in the question. I will try to run this on my actual data. Thanks. Up-Voted.
in your output details appears twice for insurance 'Sigma'. It should appear only once since we are trying to categorize all other data based on 'insurance'
@moys, do you want the details to be a array of object then?
yes. I think I missed the square brackets there. We have to first map name with insurance & for each insurance, an array of the name plus the relevance data.
In this code also, it seems that the assumption is made that "For each nodes inside the current array, loop through the keys. The keys other than name and item are supposed to be dates." This is an assumption it works as of now, but if the data changes, this can change & the code may not work. The code gives the result as expected, may not be future proof.
|
2

Checked with the syntax of the filteredData. But it seems that the details node in each object of filteredData array must be an array, since there are multiple nodes with key as name.

Logic

  • Loop through the current array.
  • For the each object in current array find a matching node from history array having same name.
  • For each nodes inside the current array, loop through the keys. The keys other than name and item are supposed to be dates.
  • Create a detail object with name as the matching name from history array and an empty values list.
  • Generate the values for each date with calculation for risk.
  • Push this details to the accumulator array.
  • Before pushing verify whether a node already exist with same insurance name in the accumulator array. If there is already a node exist, the newly created detail object is to be pushed to the details array of that node, or else push a new node to the accumulator array.

Working Example

const history = [
  {
    name: "Lance",
    baseline: { risk: "112", age: "45", insurance: "Star" },
  },
  {
    name: "Sam",
    baseline: { risk: "9", age: "21", insurance: "Sigma" },
  },
  {
    name: "Jill",
    baseline: { risk: "15", age: "21", insurance: "Sigma" },
  },
  {
    name: "Bill",
    baseline: { risk: "15", age: "21", insurance: "Mercy" },
  },
];
const current = [
  {
    name: "Lance",
    item: "PS",
    "3-Aug-21": "117",
    "4-Aug-21": "120",
    "5-Aug-21": "112",
  },
  {
    name: "Sam",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },

  {
    name: "Jill",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },
  {
    name: "Bill",
    item: "PS",
    "3-Aug-21": "10.14",
    "4-Aug-21": "10.2",
    "5-Aug-21": "10",
  },
];

const output = current.reduce((acc, curr) => {
  // Find the node from the array `history` having the same name from array `current`
  const historyNode = history.find(node => node.name === curr.name);
  const details = [];
  const detail = {
    name: historyNode.name,
    values: [],
  }
  // Loop through each keys in the object `curr`
  // If the node is not `name` and `item` then defenitely its a date
  Object.keys(curr).forEach((key) => {
    if (key !== 'name' && key !== 'item') {
      // Push the date values against the name
      detail.values.push({
        date: key,
        risk: (+curr[key] / +historyNode.baseline.risk * 100).toFixed(1)
      })
    }
  })
  details.push(detail)

  // Find for a node an insurance same as that we found match from the history array.
  // If there is a match found, then this details must be pushed to the `details` array of that particular node
  const accumulatorNode = acc.find((node) => node.insurance === historyNode.baseline.insurance);
  if (accumulatorNode) {
    accumulatorNode.details.push(detail);
  } else {
    // If there is no node existing with same insurance name, then we need to insert a new object to the accumulator
    acc.push({
      insurance: historyNode.baseline.insurance,
      details,
    })
  }
  return acc;
}, []);
console.log(output)

3 Comments

"For each nodes inside the current array, loop through the keys. The keys other than name and item are supposed to be dates." This is an assumption it works as of now, but if the data changes, this can change & the code may not work. The code gives the result as expected, may not be future proof. Up-voted.
@moys your aprved answer also uses this assumption. Update the nodes inside the current array and see the code breakes beautifully. See this fiddle to see how the code works with an updated data jsfiddle.net/0wvf5du2
@moys then what is the criteria to identify the dates?

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.