Home > OS >  Find object in array of object by keys and value
Find object in array of object by keys and value

Time:04-05

I need to return part of the object which meet some condition. I get API response with the following example:

const response: ApiResponse = {
          valid: true,
          start: false,
          stop: true
        };

And based on that response I need to check my configuration object and check if there is some object witch meets the response. My config looks like this (can be modified if there is a better way to model it)

public readonly modalDataConfig: ModalDataConfig[] = [
    {
      conditions: [
        {
          start: true,
          valid: true,
        },
      ],
      p1: {
        title: `Name p1 A`,
        description: `description p1 A`,

      },
      p2: {
        title: `Name p2 B`,
        description: `description p2 B`,

      },
    },
    {
      conditions: [
        {
          valid: false,
          stop: true,
        },
      ],
      p1: {
        title: `Name p1 C`,
        description: `description p1 C`,

      },
      p2: {
        title: `Name p2 C`,
        description: `description p2 C`,

      },
    },
    {
      conditions: [
        {
          start: false,
          valid: false,
        },
      ],
      p1: {
        title: `Name p1 D`,
        description: `description p1 D`,

      },
      p2: {
        title: `Name p2 D`,
        description: `description p2 D`,

      },
    },
  ];

So I need to check if there is an object inside of the modalDataConfig.conditions which meets the response conditions. If yes I need to return either p1 or p2 from that object. I get always 3 conditions from API but my configuration condition usually uses just 2 of them. So I need to check keys and values. In the example I should get the first object since it conditions array has start: true and valid: true. TSPlayground Edit: I need to return p1 or p2 from the correct object based on the param which I know beforehand. So in the example I can assume:

const context = Producer.P1;

where AppContext is enum

 enum Producer {
  P1 = 'p1',
  P2 = 'p2',
}

CodePudding user response:

To find an object that satisfies conditions, you need decompose each conditions object into key and value and compare their result with the target value in the ApiResponse

modalDataConfig=[{conditions:[{start:true,valid:true}],p1:{title:`Name p1 A`,description:`description p1 A`},p2:{title:`Name p2 B`,description:`description p2 B`}},{conditions:[{valid:false,stop:true}],p1:{title:`Name p1 C`,description:`description p1 C`},p2:{title:`Name p2 C`,description:`description p2 C`}},{conditions:[{start:false,valid:false}],p1:{title:`Name p1 D`,description:`description p1 D`},p2:{title:`Name p2 D`,description:`description p2 D`}}];

ApiResponse = {valid: true, start: true, stop: true};

const { p1, p2 } = modalDataConfig.find(({ conditions }) => 
     Object.entries(conditions.at(0))
     .every(([key, value]) => ApiResponse[key] === value));

console.log('P1 is:', p1, 'P2 is:', p2);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

Edit

We can also simplify my solution based on a commenter's suggestion! This function removes the need to use 1/0 and simply checks if all the elements in the array are truthy.

const checkResponse = (modalDataConfig, response) => {
  let res = []
  for (const conf of modalDataConfig) {
    let cond = conf.conditions
    let isSame = Object.keys(cond)
      .map(key => response?.[key] == cond[key]).every(Boolean)
    if (isSame) res.push(conf)
  }

  return res
}

Note

In my solution, I am assuming that we only care if the key:value pairs in the conditions of the config are the same as the key:value pairs in the response, and not the other way around. This means that if there exists a key in response but not in the config, we do not use that key for our similarity check.

Steps

  1. I would first change how the ModelDataConfig is modeled, by replacing the value of the condition key to just be an object instead of an array of objects.

  2. I will first iterate through each element in modelDataConfig

  3. Within the conditions object of each element, I compare its key:value with the response, by checking 2 conditions - (1) if the key exists in response and if the value of that key is the same in both the element and response. If it satisfies both of this condition, I return a 1, else a 0. At the end, I get an array of 1s and 0s.

  4. For the response to satisfy the conditions, there can only be 1s in the array, because having a zero means that either they key doesn't even exist in the response, or the keys have different values. To check if there are only 1s, I reduce the array by using a bitwise AND operator.

  5. If the final result after reduction is 1, it means that the particular element of the modelDataConfig is the one you are looking for.

Example

const modalDataConfig = [{
    conditions: {
      start: true,
      valid: true,
    },
    p1: {
      title: `Name p1 A`,
      description: `description p1 A`,

    },
    p2: {
      title: `Name p2 B`,
      description: `description p2 B`,

    },
  },
  {
    conditions: {
      valid: false,
      stop: true,
    },
    p1: {
      title: `Name p1 C`,
      description: `description p1 C`,

    },
    p2: {
      title: `Name p2 C`,
      description: `description p2 C`,

    },
  },
  {
    conditions: {
      start: false,
      valid: false,
    },
    p1: {
      title: `Name p1 D`,
      description: `description p1 D`,

    },
    p2: {
      title: `Name p2 D`,
      description: `description p2 D`,

    },
  },
  {
    conditions: {
      start: false,
      valid: true,
    },
    p1: {
      title: `Name p1 D`,
      description: `description p1 D`,

    },
    p2: {
      title: `Name p2 D`,
      description: `description p2 D`,

    },
  },
];



const checkResponse = (modalDataConfig, response) => {
  let res = []
  for (const conf of modalDataConfig) {
    let cond = conf.conditions
    let isSame = Object.keys(cond)
      .map(key => key in response && response[key] == cond[key] ? 1 : 0)
      .reduce((a, b) => a & b, 1)

    if (isSame) res.push(conf)
  }

  return res
}

const response1 = {
  valid: true,
  start: false,
  stop: true
};
console.log('Results with response1:')
console.log(checkResponse(modalDataConfig, response1))

const response2 = {
  valid: false,
  stop: true
};
console.log('Results with response2:')
console.log(checkResponse(modalDataConfig, response2))

  • Related