Guide to contrasting elements within a nested object

I am trying to extract data from an auto-generated object by cleaning up duplicates and concatenating any additional entries. Here is a simplified example:

const categories = [{
  category: "mammal",
  options: ["horse", "cow"],
}, {
  category: "mammal",
  options: ["pig", "cow"],
}, {
  category: "gender",
  options: ["male"],
}, {
  category: "mammal",
  options: ["cow"],
}, {
  category: "mammal",
  options: ["pig"],
}, {
  category: "gender",
  options: ["female"],
}];

The desired output should be formatted like this:

mammal>horse;cow;pig/gender>male;female/

I have attempted to loop through the object array to compare properties but struggle with appending unique options under each category without duplications.

const newArr = [];

for (let i = 0; i < categories.length; i++) {
    categoryIsInArray = newCat.indexOf(categories[i].category) !== -1;
    if (categoryIsInArray === true) {
         // logic for handling options
    }
    else {
        newArr.push(categories[i].category)
    }
}

However, my current method only produces a limited array:

["mammal","gender"]

I believe I need to iterate over the options within each category and add them accordingly. Here is my attempt:

const newArr = [];

for (let i = 0; i < categories.length; i++) {
    categoryIsInArray = newCat.indexOf(categories[i].category) !== -1;
    if (categoryIsInArray === true) {
        for (let j = 0; j < categories[i].options.length; j++) {
            optionIsInArray = newCat.indexOf(categories[i].options[j]) !== -1;
            if(optionIsInArray === false) {
                newCat.push(categories[i].options)
            }
        }
    }
    else {
        newArr.push(categories[i].category)
    }
}

Unfortunately, this approach has not yielded the desired result and has mixed up the structure. Any advice on how I can modify this to achieve my goal?

Answer №1

You could categorize items by their type and utilize a Set to store distinct options.

const
    types = [{ type: "animal", options: ["cat", "dog"] }, { type: "animal", options: ["bird", "dog"] }, { type: "color", options: ["red"] }, { type: "animal", options: ["dog"] }, { type: "animal", options: ["bird"] }, { type: "color", options: ["blue"] }],
    result = Object
        .entries(types.reduce((r, { type, options }) => {
            options.forEach(Set.prototype.add, r[type] ??= new Set);
            return r;
        }, {}))
        .map(([key, values]) => `${key}>${[...values].join(';')}/`)
        .join('');

console.log(result);

Answer №2

This unique solution showcases a different approach to implementing a reduce method. The focus here is on achieving the uniqueness of final category arrays. By concatenating the current `options` array with an initially empty array that later gets grouped by a specific `category` key, we create or reassign an instantly computed array of unique string values. This computation involves creating a Set instance from the merged array and then spreading it back into an array value.

const optionsByCategoryLookup = categories
  .reduce((result, item) => {

    // - destructure the currently processed array item.
    const { category, options } = item;

    // - aggregate the final `result`, an object, used as lookup,
    //   which is going to feature key-value pairs (entries), where
    //   the key is the `category` value, and the value is ...
    result[category] = [
      // ... the ever newly calculated array 
      //     of unique `options` string-values.
      ...new Set(
        (result[category] ?? []).concat(options)
      )
    ];
    return result;  

  }, {});

console.log({ optionsByCategoryLookup });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  const categories = [{
    category: "mammal",
    options: ["horse", "cow"],
  }, {
    category: "mammal",
    options: ["pig", "cow"],
  }, {
    category: "gender",
    options: ["male"],
  }, {
    category: "mammal",
    options: ["cow"],
  }, {
    category: "mammal",
    options: ["pig"],
  }, {
    category: "gender",
    options: ["female"],
  }];
</script>

In order to reuse the reduce functionality, one can implement it as a function statement...

function aggregateCategoryBasedOptionsLookup(
  result, { category, options }
) {
  result[category] = [
    ...new Set(
      (result[category] ?? []).concat(options)
    )
  ];
  return result;  
}

const optionsByCategoryLookup = categories
  .reduce(aggregateCategoryBasedOptionsLookup, {});

console.log({ optionsByCategoryLookup });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  const categories = [{
    category: "mammal",
    options: ["horse", "cow"],
  }, {
    category: "mammal",
    options: ["pig", "cow"],
  }, {
    category: "gender",
    options: ["male"],
  }, {
    category: "mammal",
    options: ["cow"],
  }, {
    category: "mammal",
    options: ["pig"],
  }, {
    category: "gender",
    options: ["female"],
  }];
</script>

Edit

The initial ambiguity about the expected result prompted the above approach. It is necessary to unify and normalize the data structure. The lookup object acts as an intermediate step for computing the final string-based result, emphasizing the benefits of small, reusable functions...

function aggregateCategoryBasedOptionsLookup(
  result, { category, options }
) {
  result[category] = [
    ...new Set(
      (result[category] ?? []).concat(options)
    )
  ];
  return result;  
}
function createStringBasedCategoryGraph(lookup) {
  // mammal>horse;cow;pig/gender>male;female/
  return Object
    .entries(lookup)
    .map(([key, value]) =>
      `${ key }>${ value.join(';') }/`
    )
    .join('');
}

const categoryGraph = createStringBasedCategoryGraph(
  categories
    .reduce(aggregateCategoryBasedOptionsLookup, {})
);
console.log({ categoryGraph });
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  const categories = [{
    category: "mammal",
    options: ["horse", "cow"],
  }, {
    category: "mammal",
    options: ["pig", "cow"],
  }, {
    category: "gender",
    options: ["male"],
  }, {
    category: "mammal",
    options: ["cow"],
  }, {
    category: "mammal",
    options: ["pig"],
  }, {
    category: "gender",
    options: ["female"],
  }];
</script>

Answer №3

One way to organize your array is by grouping sets based on unique category values, then transforming them into arrays. Afterwards, you can convert the final result into any desired string format:

const grouped = categories.reduce((r, {category, options}) => (options.forEach(o => (r[category]??=new Set).add(o)), r), {});
const result = Object.keys(grouped).reduce((r, key) => (r[key] = [...grouped[key]], r), {});
console.log(result);
<script>
const categories = [
    {
        category: "mammal",
        options: ["horse", "cow"]
    },
    {
        category: "mammal",
        options: ["pig", "cow"]
    },
    {
        category: "gender",
        options: ["male"]
    },
    {
        category: "mammal",
        options: ["cow"]
    },
    {
        category: "mammal",
        options: ["pig"]
    },
    {
        category: "gender",
        options: ["female"]
    }
];
</script>

Answer №4

const categories = [{
  category: "mammal",
  animal: ["horse", "cow"],
}, {
  category: "mammal",
  options: ["pig", "cow"],
}, {
  category: "gender",
  options: ["male"],
}, {
  category: "mammal",
  options: ["cow"],
}, {
  category: "mammal",
  options: ["pig"],
}, {
  category: "gender",
  options: ["female"],
}];

const result = {};

for (let i = 0; i < categories.length; i++) {
    const currentCategory = categories[i].category;
    const currentOptions = categories[i].options || categories[i].animal || [];

    if (!result[currentCategory]) {
        // If the category doesn't exist in the result object, create an array for it
        result[currentCategory] = [];
    }

    for (let j = 0; j < currentOptions.length; j++) {
        const currentOption = currentOptions[j];
        if (result[currentCategory].indexOf(currentOption) === -1) {
            // If the option doesn't exist in the category, add it
            result[currentCategory].push(currentOption);
        }
    }
}

console.log(result);

This script defines a new object called 'result' to store processed data and then goes through each element in the original array. It checks whether each category already exists in the 'result' object and appends unique options to that specific category without duplicates.

The final 'result' object will consist of keys representing categories, each linked to an array containing only distinct options.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Omitting certain $fields when querying a document from MongoDB

Is it possible to retrieve a document from MongoDB in its original form without some fields being converted to objects containing $ fields? For instance, I have a field called timestamp where I store a long value. Initially, it used to return just the val ...

Tips for optimizing the performance of a React application when deploying it to Azure

After successfully deploying my application to Azure Web Apps, I encountered an issue with the response time. The client is located in one folder and the server in another. When accessing the application at , it takes approximately 15 seconds for the page ...

Struggling with React integration of AdminLTE3 sidebar treeview?

I have a requirement to create a React sidebar with a category 'Staff' that, when clicked, reveals three subordinate categories. Below is the code snippet: import React, { Component } from "react"; export default class Sidebar extends Componen ...

The delete_node() function in jstree does not seem to be removing nodes

In my attempt to create a custom context menu for different nodes, I've managed to display different labels for clicks on folders or files. However, I am facing some challenges when trying to delete them. Take a look at my code snippet. Due to diffic ...

Using conditional logic to render components in VueJS

How can I conditionally display content in a parent component based on a user input variable? If the userinput variable is false, I want to remove the <div class="parent"> and show the PopUp component instead. I've tried using `v-if` ...

Populating a string array in Android using data from an SQLite database

While attempting to customize the Google notepad tutorial for utilizing SQLite databases to store GPS coordinates, I encountered a challenge. The issue lies in populating an array from the database so that I can draw the locations on the map. private void ...

Passing data from a Vue.js component to a router in index.js

I am attempting to transmit a JWT token value from the component Login.vue and verify it in the router/index.js before directing the user to the next page. Login.vue: <script> import axios from "axios"; export default { name: "Login", m ...

Can Mongoose handle document arrays editing and version control efficiently?

Currently working on a web application using Node.js and MongoDB/Mongoose, the main model in our project is Record which contains numerous subdocument arrays such as "Comment", "Bookings", and "Subscribers". However, when users click the delete button in ...

Update the chosen option in a dropdown list with jQuery and javascript

I need to set the value of a column in a repeater so that once it's assigned, the column will display the current selection from the dropdown. I have the correct value to assign in $('#myname_' + rowIndex).text(), but when I try to assign t ...

Difficulty with AngularJs Translation Partials

I have encountered an issue with binding translation. Some objects are converting to their translated value successfully, while others, as mentioned below, are not working. This problem only occurs the first time I build the project. Upon refreshing, every ...

Ways to properly close open HTML tags using node.js?

Have you ever encountered a situation where user-entered content from a database or similar source only contains the opening tag without the closing tag? This can disrupt the layout of your website. Is there a way to fix this issue using Node.js on the s ...

Stream audio smoothly with icecast audio.js without any delays

I have set up an icecast server on my system, and the clients connecting to it will be embedded in web pages using either HTML5 or Flash. Currently, I am utilizing audio.js with a flash fallback for this purpose. The issue at hand is that the audio and a ...

Developing a RESTful API with Discord.js integrated into Express

Currently, I am faced with the challenge of integrating the Discord.js library into an Express RESTful API. The main issue at hand is how to effectively share the client instance between multiple controllers. The asynchronous initialization process complic ...

What is the reason for the exclusion of this input from a two-dimensional array and the generation of only a single output in Java?

Here are the code snippets I have been working on: for (int i = 0; i < rounds; i++){ result = rotate(result); res[i] = result; } System.out.println(Arrays.toString(res[1])); Despite monitoring the output from the r ...

Creating a multi-filter gallery similar to the one found in WooCommerce or eCommerce platforms involves integrating various filters to allow

Looking for a dynamic multifilter gallery similar to WooCommerce/ecommerce product filters? We have three types of filter dropdowns: COLOR, SIZE, and SHAPE. For example, if you select color: red and green, size: small, and shape: round The filtering wil ...

Determine if a draggable item is currently positioned over another element

In my body, there are several divs located: <div id="one"></div> <div id="two"></div> <div id="three"></div> All of these divs are draggable using jqueryUI: var $divs = $('#one, #two, #three'); $divs.draggab ...

Is it possible to combine pixi.js and three.js in the same project?

Can we create 2D graphics using pixi.js, and then introduce 3D elements from three.js into the same composition? Is it also feasible to rotate 2D objects made in pixi within a 3D environment? For instance, is it attainable to craft a user interface in 2D ...

Top method for removing quotation marks from form input using jquery

Here is a form input that I need to handle: <tr class="formulaRow"> <input type="text" class="ingredient required" name="ingredient"> </tr> Currently, the value from this input is stored as follows: var ingredient = $(".formulaRow").fi ...

The sample Ajax XML code provided by W3Schools is ineffective

While studying xml parsing in ajax on w3schools.com, I came across an example that functioned perfectly online. However, when I saved it to my desktop as abc.html and note.xml, the XML values weren't displaying. Even though the HTML elements were vis ...

If you try to wrap an object with an anonymous function, you'll receive an error message

Consider the following straightforward example. (function() { var message = { display: function() { alert('hello'); } }; })(); When trying to implement message.display(); An error is triggered stating ReferenceError: message ...