2

I am still fairly new to JavaScript and need help with a task I am trying to accomplish.

I have an array of objects like this:

    const data =
{
    "Total_packages": {
        "package1": {
            "tags": [
                "kj21",
                "j1",
                "sj2",
                "z1"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name",
                    "lastName": "lastName",
                    "purchase": [
                        {
                            "title": "title",
                            "category": [
                                "a",
                                "b",
                                "c"
                            ]
                        }
                    ]
                }
            ]
        },
        "package2": {
            "tags": [
                "s2",
                "dsd3",
                "mhg",
                "sz7"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name1",
                    "lastName": "lastName1",
                    "purchase": [
                        {
                            "title": "title1",
                            "category": [
                                "a1",
                                "b1",
                                "c1"
                            ]
                        }
                    ]
                }
            ]
        },
        "package3": {
            "tags": [
                "s21",
                "dsd31",
                "mhg1",
                "sz71"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name2",
                    "lastName": "lastName2",
                    "purchase": [
                        {
                            "title": "title2",
                            "category": [
                                "a2",
                                "b2",
                                "c2"
                            ]
                        }
                    ]
                }
            ]
        },
        "package4": {
            "tags": [
                "s22",
                "dsd32",
                "mhg2",
                "sz72"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name3",
                    "lastName": "lastName3",
                    "purchase": [
                        {
                            "title": "title3",
                            "category": [
                                "a3",
                                "b3",
                                "c3"
                            ]
                        }
                    ]
                }
            ]
        },
        "package5": {
            "tags": [
                "s22",
                "dsd32",
                "mhg2",
                "sz72"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name4",
                    "lastName": "lastName4",
                    "purchase": [
                        {
                            "title": "title4",
                            "category": [
                                "a4",
                                "b4",
                                "c4"
                            ]
                        }
                    ]
                }
            ]
        }
    }
}

    var arrRand = genNum(data, 3);
    console.log(arrRand);

               function genNum(data, loop='') {
                    var list = [];
                    var arrayOfTags = Object.entries(data.Total_packages).reduce((acc, [k, v]) => {
                        if (v.tags) acc = acc.concat(v.tags.map(t => ({tag: t, response: v.expectedResponse})));
                        return acc;
                    }, []);
                    for (var i = 0; i < loop; i++){
                      var randomIndex = Math.floor(Math.random() * arrayOfTags.length);
                    var randomTag = arrayOfTags[randomIndex];
                    list.push(randomTag);
                    }
                    return list;

        }

I then access the values I need by doing something like arrRand[0].tag and arrRand[0].response.

Often times I get duplicate responses from the method such as following and it becomes problematic:

[
  {
    "tag": "s22",
    "response": [
      {
        "firstName": "Name4",
        "lastName": "lastName4",
        "purchase": [
          {
            "title": "title4",
            "category": [
              "a4",
              "b4",
              "c4"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  }
]

My goal is to send API requests with a random "tags" value from above and then match the response I get from the call to the expectedResponse part of the data.

My initial thought was to do something like:

data.Total_packages.tags[Math.floor(Math.random() * data.Total_packages.tags.length)];

However, I can't call on "tags" without traversing through its parent i.e "package1" or "package2", so then it won't be random anymore.

I know there is probably a very simple way to do it that I am not getting. Any advice would be appreciated.

2
  • you mean you want one whole array with all tags from both "packages"? Commented Aug 30, 2022 at 15:24
  • @joe No, I need one value from the "tags" tag from either packages. That tag will be run on the API call, and then which "package" that tag belonged to, I will match the response to the "expectedResponse" tag and make sure they match. Commented Aug 30, 2022 at 15:28

3 Answers 3

2

You could build an array from the various tags elements, and use that to do random things.

const data =
{
    "Total_packages": {
        "package1": {
            "tags": [
                "kj21",
                "j1",
                "sj2",
                "z1"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name",
                    "lastName": "lastName",
                    "purchase": [
                        {
                            "title": "title",
                            "category": [
                                "a",
                                "b",
                                "c"
                            ]
                        }
                    ]
                }
            ]
        },
        "package2": {
            "tags": [
                "s2",
                "dsd3",
                "mhg",
                "sz7"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name1",
                    "lastName": "lastName1",
                    "purchase": [
                        {
                            "title": "title1",
                            "category": [
                                "a1",
                                "b1",
                                "c1"
                            ]
                        }
                    ]
                }
            ]
        }
    }
}

const arrayOfTags = Object.entries(data.Total_packages).reduce((acc, [k, v]) => {
  if (v.tags) acc = acc.concat(v.tags.map(t => ({tag: t, response: v.expectedResponse})));
  return acc;
}, []);

const randomIndex = Math.floor(Math.random() * arrayOfTags.length);

const randomTag = arrayOfTags[randomIndex];

console.log(randomTag.tag, randomTag.response);

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

8 Comments

This worked well, however, it seems to combine both sets of "tags" and picks one randomly from them. I am sorry if I wasn't clear but I need one value from either "tags" instances and then grab its respective response.
random tag from package 1 + response from package 1, random tag from package 2 + response from package 2?
Each API call will pick a random tag from above and then match the response from the API call to the response for that tag above. So if the tag happens to be picked from package 1, then response for package 1 will be picked.
Modified. Now it includes the response for each tag in the array of tags. So you can pick one at random, check the tag property and check the response property.
I would use a shuffling algorithm like Fisher-Yates, see stackoverflow.com/questions/2450954/…
|
1

You will need to mine the tags, put them together into an array and randomize the index, finally get the value there. The solution below assumes that your tags are all arrays inside data.Total_packages[whateverpackage]

const data =
{
    "Total_packages": {
        "package1": {
            "tags": [
                "kj21",
                "j1",
                "sj2",
                "z1"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name",
                    "lastName": "lastName",
                    "purchase": [
                        {
                            "title": "title",
                            "category": [
                                "a",
                                "b",
                                "c"
                            ]
                        }
                    ]
                }
            ]
        },
        "package2": {
            "tags": [
                "s2",
                "dsd3",
                "mhg",
                "sz7"
            ],
            "expectedResponse": [
                {
                    "firstName": "Name1",
                    "lastName": "lastName1",
                    "purchase": [
                        {
                            "title": "title1",
                            "category": [
                                "a1",
                                "b1",
                                "c1"
                            ]
                        }
                    ]
                }
            ]
        }
    }
}

let tags = [];
for (let key in data.Total_packages) {
    if (data.Total_packages[key].tags) tags = tags.concat(data.Total_packages[key].tags);
}
console.log(tags[parseInt(tags.length * Math.random())]);

EDIT

In the comment section you have mentioned that you have duplicates of the form of

[
  {
    "tag": "s22",
    "response": [
      {
        "firstName": "Name4",
        "lastName": "lastName4",
        "purchase": [
          {
            "title": "title4",
            "category": [
              "a4",
              "b4",
              "c4"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  }
]

This is how you can get rid of duplicates:

let input = [
  {
    "tag": "s22",
    "response": [
      {
        "firstName": "Name4",
        "lastName": "lastName4",
        "purchase": [
          {
            "title": "title4",
            "category": [
              "a4",
              "b4",
              "c4"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  },
  {
    "tag": "dsd31",
    "response": [
      {
        "firstName": "Name2",
        "lastName": "lastName2",
        "purchase": [
          {
            "title": "title2",
            "category": [
              "a2",
              "b2",
              "c2"
            ]
          }
        ]
      }
    ]
  }
];

let output = input.filter((item, index) => {
    return input.filter((item2, index2) => {
        return ((item.tag === item2.tag) && (index2 < index));
    }).length === 0;
});

console.log(output);

We search for items who have no matches on earlier indexes.

17 Comments

thank you for your suggestion. I am sorry for not being clear before, I also needed the corresponding "expectedResponse" item from each "tag" as well. Each of these random values need to be unique and not repeat. I did get responses from others that were helpful as well but I also wanted to make it clearer here. Thanks again.
@hungryhippos how should the output look alike?
@hungryhippos edited my answer, added a snippet that eliminates the duplicates from your example.
@hungryhippos I have a nested call for .filter(). The outer call searches for items that do not have a match in the inner call for .filter(). The inner call for .filter() takes the "current" element and index (item and index, respectively) and checks whether there exists another element and index (item2 and index2, respectively) whose tag matches the tag of item, but index2 < index. If this condition is met for any element, then the outer filter will exclude item from the results.
@hungryhippos in other words, the two filters basically ensure that only the earliest tag from the array will be taken into account, therefore duplicates with higher indexes will be ignored. If my answer solved your problem, then you may consider accepting it as the correct answer.
|
1

i saved all tags in a separate array and kept the ref of expectedResponse in the block. then it's a matter or randomly selecting one tag index and matching with the block expectedResponse index. probably needs some adjustment to the random/length but i hope it puts you in the right direction.

var tags = []
var block = Object.values(data.Total_packages).flat()
block.forEach(item => tags = [...tags, ...item.tags])

var index = tags[parseInt(tags.length * Math.random())]
console.log(block[Math.floor(tags.indexOf(index) / 4)].expectedResponse)

4 Comments

This is great, thank you! Can you explain why in the last line, you are dividing by 4? I am getting an out of bounds error around half the time I run this.
because there are 4 tags in each node, but when indexOf returns a match "position 3", it is part of the first element in block floor(3/4) = index 0, "position 5" floor(5/4) = index 1. it sounds like your block array has only one entry, hence why out of bounds if the index is greater than zero.
Well done, I understand now and really appreciate your answer. One last question: if my list of total tags changes in the future, is there a way I can make the /4 part agnostic of total number of elements under tags? Like couldn't I do something like /length of tags? That way I don't have to keep going and changing the total number of tags IF they change?
sure can do that. it wont work if the number of tags is not the same in every node though, otherwise i think it will do the trick for you.

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.