Ways to decrease a value in an array comprised of nested arrays

Within my array of products, each product contains an array of categories. My goal is to extract and return the unique values of the type property from the category object.
Both the Lodash and standard versions provided below accomplish this task.
I am interested in creating a versatile function that accepts the property path as input and outputs unique values.

I envision something concise like

map(products, property("categories[].type")
but here are the detailed versions:

import { compact, flatten, map, property, uniq } from "lodash";

export const getAllTypes1 = (products) => {
  return uniq(
    compact(map(flatten(map(products, property("categories"))), "type"))
  );
};
export const getAllTypes2 = (products) => {
  const types = [];
  products.forEach((product) => {
    product.categories.forEach((category) => {
      if (!types.some((t) => t === category.type)) {
        types.push(category.type);
      }
    });
  });
  return types;
};

Example data

const product1 = {
  name: 'Wilson Orange',
  price: 72.50,
  categories: [{
    type: 'flash sale',
    discountable: false,
  },{
    type: 'tennis',
    discountable: true,
  }]
};
const product2 = {
  name: 'Babolat Green',
  price: 65.50,
  categories: [{
    type: 'tennis',
    discountable: true,
  }]
};
const products = [product1, product2];

Result

const result = getAllTypes2(products);
console.log(result); // ["flash sale", "tennis"]

Visit this live example

Answer №1

Presented here is a pure JavaScript function that navigates through the provided path without requiring [] and efficiently handles arrays within the structure.

The functionality can be described as follows:

  1. Initialize an empty Set to handle duplicate elimination
  2. Convert the path string into an array of properties -> props
  3. Invoke a recursive function recurse(currObj, props) which:
    1. Checks if the current object currObj is an array, and if so: a. Recurse with each individual element within the array of values b. Use the same set of props since an object has not been encountered in the path
    2. Determine if the final property in the path has been reached, if true a. Add the corresponding value of the property from the current object to the Set
    3. In all other cases, recursively call currObj[currProp] with the remaining properties
  4. Transform the Set back to an array and return it.

const product1 = {
  name: 'Wilson Orange',
  price: 72.5,
  categories: [
    {
      type: 'flash sale',
      discountable: false,
    },
    {
      type: 'tennis',
      discountable: true,
    },
  ],
};
const product2 = {
  name: 'Babolat Green',
  price: 65.5,
  categories: [
    {
      type: 'tennis',
      discountable: true,
    },
  ],
};
const products = [product1, product2];

function getProperties(array, path) {
  const props = path.split('.');
  const values = new Set();

  function recurse(currObj, props) {
    const currProp = props[0]
    const nextProps = props.slice(1);
    if (Array.isArray(currObj)) {
      for (let val of currObj) {
        recurse(val, props);
      }
      return
    }
    if (nextProps.length === 0) {
      values.add(currObj[currProp])
    } else {
      recurse(currObj[currProp], nextProps)
    } 
  }
  recurse(array, props);
  return [...values];
}

console.log(getProperties(products,'categories.type'))
console.log(getProperties(products,'price'))
console.log(getProperties(products,'name'))

Answer №2

While not a traditional property path string, the following code is succinct and expressive:

const pipe = (...funcs) => funcs.reduceRight(
  (nextFunc, func) => data => func(data, nextFunc), data => data,
);
const getAllTypes = pipe(
  (data, nextFunc) => [...new Set(data.flatMap(nextFunc))],
  (data, nextFunc) => data.categories.map(nextFunc),
  (data) => data.type,
);

const products = [{
  name: 'Wilson Orange',
  price: 72.50,
  categories: [{
    type: 'flash sale',
    discountable: false,
  }, {
    type: 'tennis',
    discountable: true,
  }]
}, {
  name: 'Babolat Green',
  price: 65.50,
  categories: [{
    type: 'tennis',
    discountable: true,
  }]
}];

console.log(getAllTypes(products));

The data => data parameter in pipe allows it to be called with no arguments and return the identity function. It also ensures that the last function in pipe can accept a nextFunc argument for consistency, making the code more streamlined.

For further information, refer to:

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

AngularJS right-click menu

I need a context-menu directive that can provide information on the clicked element for proper reaction. Although I experimented with this module, I'm facing an issue in uniquely identifying the clicked element. This is hindering my ability to apply ...

The asynchronous functionality of Azure IoT Edge node SDK's invokeDeviceMethod seems to be malfunctioning

I am attempting to asynchronously return a result for a direct method call. This is what I attempted: const client = Client.fromConnectionString(process.env.AZ_IOT_CONNECTION_STRING); const methodParams = { methodName: "method", payload: 10, // Numbe ...

Having trouble receiving a response in my JavaScript function with EJS

I'm attempting to retrieve the status of an address using the request_withd function. This function calls another function named 'is_address_exist' which is supposed to return the response status of the address as either 'yes' or & ...

"Disabling ThreeJS HDR feature seems to stay off permanently, without any option

I've been working on toggling a HDR map in three.js. This is how I set it up: //HDR LOADER var envmaploader = new THREE.PMREMGenerator(renderer); const loadhdri = new THREE.RGBELoader() .load("myhdr.hdr", function (texture){ texture.mapping = THREE. ...

Timing of React setState updates

Currently, I am working on developing a memory game using React. The main objective of the game is to click on cards without repeating any selections in order to earn points. If the same card is clicked twice, it results in losing the game. This project se ...

Exploring the possibilities of Three.JS by manipulating the world position of a child 3D object

I have a child object3D that is part of a group Object3D. While the child object's position is displayed relative to the parent object's space, I am trying to change the location of the child object within the 3D space. To do this, I first need t ...

Is there a way to transform a local array into remote JSON data?

I am attempting to retrieve an array from a remote server that is connected to a dynamic database. From what I have gathered on Ionic forums, it seems that I need to utilize the $http function from AngularJS. However, since I am new to AngularJS, the curr ...

Parallax Effect Slows Down When Scrolling In Web Page

Currently in the process of creating a website with a scrolling parallax effect using Stellar.js on the header and three other sections. However, I'm experiencing lag when scrolling, especially at the top of the page. I've attempted to reduce la ...

Ajax does not refresh only a specific part of the page; rather, it refreshes the

Using .NET web services, I have encountered a problem with my ajax call attached to the master page via JS. It seems that upon successful execution of the function, the entire page is getting refreshed instead of just a specific part. I have experimented w ...

Encountering 'undefined' issue with find operation in mongoDB

Seeking assistance to utilize all available values in my code. bericht.find({ room: room }).toArray(function(err, docs) { assert.equal(err, null); str2 = str2 + docs.message; The function I'm using can successfully loca ...

Right-align each item when selecting none

Is there a way to change the style of just one of the elements select or option, without affecting the style of both? I attempted to align the select element to the right, while leaving the option elements aligned to the left. However, this did not work a ...

Previewing an uploaded image before submitting with FileBase64: A step-by-step guide

How can I implement a preview for an uploaded image before submitting the form? I have the upload functionality working but I would like to add a preview feature for the image. Below is the code snippet I am currently using: const [shop, setShop] = us ...

Modify the status of a current object

Hi there, I am currently working with React context and have run into an issue that I need help with. The main component where all the logic resides is as follows: import React , {useContext} from 'react'; import {TodoContext} from '../../ ...

Add letters to the input field as soon as typing begins without the need to first click on the input field when

Take a look at the code below: document.addEventListener('keyup', logKey); function logKey($event) { var charCode = $event.keyCode; if(charCode > 31 && (charCode < 48 || charCode > 57 || charCode > 107 || charCode > ...

Determine the specific element that the finger is touching when a touchend event occurs

My goal is to determine which HTML element was touched by the finger when the touchend event is triggered. The current code I have implemented looks like this: $('.wsSquare').on("mouseup touchend",function(event){ event.preventDefault(); ...

Node.js express version 4.13.3 is experiencing an issue where the serveStatic method is not properly serving mp3 or

I am currently utilizing Express 4.13.3 along with the serve-static npm module to serve static assets successfully, except for files with mp3 or ogg extensions. Despite reviewing the documentation, I have not come across any information indicating that thi ...

Finding the square root of a cell array using MATLAB

Looking for advice on how to calculate the square root of all elements in a cell array A={<2x6 double>,<4x6 double>,<16x6 double>}. While using sqrt is simple for a single matrix, I'm wondering if there's a solution for a cell a ...

What is the best way to showcase the character and word count on the Redactor rich text / html editor?

Recently, I made the decision to switch from CKEditor to Redactor due to numerous issues with AJAX updates on the DOM. In the past, we relied on a CKEditor plugin for character count in our rich text editor. Is there a way to implement this same feature ...

Converting JSON into Typescript class within an Angular application

As I work on my app using angular and typescript, everything is coming together smoothly except for one persistent issue. I have entity/model classes that I want to pass around in the app, with data sourced from JSON through $resource calls. Here's ...

jQuery's :last selector allows you to target the last

I need assistance with my jQuery code $('#share_module:last').css("background-color","red"); Unfortunately, it is only affecting the first #share_module Here is an example of the HTML structure: <div id = "share_module" class = "id of the ...