Using a sequence of array methods like filter, map, and reduce in succession instead of relying on a double loop

Having encountered a perplexing issue that I can't seem to comprehend... here is what I am attempting to achieve.

Presented with the following array of objects,

products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

My initial approach involved using nested loops to add keys based on ingredient names and incrementing the count as I iterate through, like so:

let ingredientCount = {}; 

for (i = 0; i < products.length; i += 1) {
    for (j = 0; j < products[i].ingredients.length; j += 1) { //loop ingredients 
        ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1; 
    }
}

The resulting ingredientCount object should resemble: { "artichoke": 1 "mushrooms": 2 } ***

The challenge at hand is to achieve the same outcome using map and reduce functions instead of loops.

let ingredientCount = {}

ingredientCount = 
products.filter((value) => {
    // filter out arrays within ingredients 
    // resulting in
    /* 
    [ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms']
    ,ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary']
    ,ingredients: ['black beans', 'jalapenos', 'mushrooms']
    ,ingredients: ['blue cheese', 'garlic', 'walnuts']
    ,ingredients: ['spinach', 'kalamata olives', 'sesame seeds']
    */

}).map((value) => {
    /* extract ingredients and map this array to  
    arthichoke: ['artichoke','artichoke','artichoke']
    sundried tomatoes: ['sundried tomatoes']
    etc... 
    */


}).reduce((acc, value) => {
    /* reduce arrays within each key to numbers. 
    resulting in 

    artichokes: artichokes.length (i.e. 3 )
    sundried toamatoes: 1
        
    */
})

Is there a way to achieve the same result using the array methods mentioned above without the need for loops?

Thank you in advance.

Answer №1

To achieve the desired outcome, it is essential to utilize the map(), flat(), and reduce() functions in sequence. Specifically, the flat() function plays a crucial role in flattening the array.

products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

let obj = products
              .map(p => p.ingredients)
              .flat()
              .reduce((obj, val) => {
                  obj[val] = (obj[val] || 0) + 1;
                  return obj;
              }, {});
console.log(obj);

Answer №2

This code utilizes the .reduce method and .forEach method of an array to find the occurrence of ingredients in a list of products.

var products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

var result = products.reduce((acc,obj) => 
   {obj.ingredients.forEach(ob=> acc[ob] = acc[ob]+1 || 1)
    return acc;
},{});

console.log(result);

Answer №3

A clever approach is to utilize either two forEach or map functions, while keeping track of a final array that only requires periodic updates.

let items = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

let ingredientCount = {};
items.forEach((item) => item.ingredients.forEach((ingredient) => ingredientCount.hasOwnProperty(ingredient) ? ingredientCount[ingredient]++ : ingredientCount[ingredient] = 1));
console.log(ingredientCount);

Answer №4

Utilize the Array.prototype.reduce method to iterate through the array and update the count accordingly.

const products = [{
    name: 'Sonoma',
    ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'],
    containsNuts: false
  },
  {
    name: 'Pizza Primavera',
    ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'],
    containsNuts: false
  },
  {
    name: 'South Of The Border',
    ingredients: ['black beans', 'jalapenos', 'mushrooms'],
    containsNuts: false
  },
  {
    name: 'Blue Moon',
    ingredients: ['blue cheese', 'garlic', 'walnuts'],
    containsNuts: true
  },
  {
    name: 'Taste Of Athens',
    ingredients: ['spinach', 'kalamata olives', 'sesame seeds'],
    containsNuts: true
  },
];

const result = products.reduce((accumulator, { ingredients }) => {
  ingredients.forEach((ingredient) => {
    accumulator[ingredient] = (accumulator[ingredient] || 0) + 1;
  });
  return accumulator;
}, Object.create(null));

console.log(result);

Answer №5

Implement the use of flatMap and reduce functions, along with the ?? and , operators.

const products = [
    { name: 'Sonoma', ingredients: ['artichoke', 'sundried tomatoes', 'mushrooms'], containsNuts: false },
    { name: 'Pizza Primavera', ingredients: ['roma', 'sundried tomatoes', 'goats cheese', 'rosemary'], containsNuts: false },
    { name: 'South Of The Border', ingredients: ['black beans', 'jalapenos', 'mushrooms'], containsNuts: false },
    { name: 'Blue Moon', ingredients: ['blue cheese', 'garlic', 'walnuts'], containsNuts: true },
    { name: 'Taste Of Athens', ingredients: ['spinach', 'kalamata olives', 'sesame seeds'], containsNuts: true },
];

const ingredientCount = products
  .flatMap(({ ingredients }) => ingredients)
  .reduce((acc, item) => ((acc[item] = (acc[item] ?? 0) + 1), acc), {});

console.log(ingredientCount);

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

Utilizing auto-generated Nonce for Content Security Policy in a Node.js/Express web application

I've exhausted all possible solutions in my attempt to create a nonce and pass it successfully to the CSP and inline scripts with the nonce variable. Despite reading numerous articles, the guidance on accomplishing this task remains vague. Fortunately ...

Can we make this happen? Navigate through slides to important sections, similar to vertical paging

Imagine a website with vertical "slides" that take up a significant portion of the screen. Is there a way to smoothly add vertical paging to the scrolling? For example, when the user scrolls close to a specific point on the page horizontally, the page will ...

What is the best way to trigger a function when a button is enabled in Angular 8?

Here is a portion of my sign-in.component.html file. I have created a function in the corresponding sign-in.component.ts file that I want to trigger when the button below becomes enabled. Here is an example of what I am trying to achieve: <div class= ...

Discovering the oldest date in an array with JavaScript

Is there a way to identify the earliest date, also known as the minimum date, within an array using JavaScript? For instance: ["10-Jan-2013", "12-Dec-2013", "1-Sep-2013", "15-Sep-2013"] The desired output would be: ...

Retrieve data from an external website containing an HTML table without a table ID using Java Script and transform it into JSON

I have developed a script that can convert HTML table data into a JSON Object. To accomplish this task, I utilized the jquery plugin created by lightswitch05. With this code, I am able to extract data from an HTML table on the same web page using: var t ...

Transferring files via Bluetooth on PhoneGap

As someone new to phonegap, I'm interested in transferring text files from one device to another using Bluetooth within the platform. I've looked at several examples but haven't found a solution yet. I've come across some examples that ...

Restore the button to its original color when the dropdown menu is devoid of options

Is it possible to change the button colors back to their original state automatically when a user deselects all options from my dropdown menu? The user can either uncheck each option box individually or click on the "clear" button to clear all selections. ...

Is it possible to trigger a function using an event on "Any specified selector within a provided array"?

Trying to figure out how to show/hide a group of divs with different IDs by executing a function after creating an array of IDs for the NavBar. I'm having trouble getting started, but here's what I was thinking: $.each(array1, function(i, value) ...

D3: Ensuring Map is Scaled Correctly and Oriented Correctly

I am attempting to integrate a map into a website using D3 and topoJSON that resembles the following: https://i.sstatic.net/1brVx.png However, when I create the map with D3/topoJSON, it shows up small and inverted. https://i.sstatic.net/LgQBd.png Even ...

Steps to retrieve the central coordinates of the displayed region on Google Maps with the Google Maps JavaScript API v3

Is there a way to retrieve the coordinates for the center of the current area being viewed on Google Maps using JavaScript and the Google Maps JavaScript API v3? Any help would be greatly appreciated. Thank you! ...

Transferring data from JavaScript to PHP for geolocation feature

Hello everyone, I'm looking to extract the longitude and latitude values from my JavaScript code and assign them to PHP variables $lat and $lng. This way, I can retrieve the city name and use it in my SQL query (query not provided). Below is the scrip ...

Guide to naming Vite build JS and CSS bundles in Vue

As I work on building a SPA using Vite+Vue3 and JavaScript, I have encountered an issue when running npm run build. After making changes, the resulting .css and .js files have names that appear to be generated from a hash, which is not ideal. I would like ...

Exploring the AngularJS global Date timezone offset

I want to display dates based on the users' time zones. I am hoping that Angular provides a way to globally configure the Date filter for this purpose. Doing it manually for each case doesn't seem right to me. My timestamps are already passed t ...

Tips for adding multiple elements to a NumPy array

I have a JSON file that may contain up to 10 nested dictionaries within a list. These nested dictionaries are all related to a single service request number, but each dictionary represents a different request. For example, service request 1 at address one ...

The Material UI list element fails to appear on the screen

I am encountering an issue where I am trying to display a Material UI list within a drop-down menu (using the Material UI drawer component) for mobile view, but the actual list is not appearing as expected. The code snippet for the list is as follows: con ...

Having difficulty attaching events to Bootstrap 3 button radios in button.js

Struggling with extracting the correct value from a segmented control created using the radio button component of button.js in Twitter Bootstrap 3. Upon binding a click event to the segmented control and running $.serialize() on its parent form, I noticed ...

can you explain which documents outline the parameters that are passed into the express app.METHOD callback function?

As a beginner in javascript and nodejs, I often struggle with understanding callback functions. One thing that particularly confuses me is determining what arguments are passed into a callback function. Let's consider the following example: app.get( ...

Unraveling the mystery: How does JavaScript interpret the colon?

I have a quick question: When I type abc:xyz:123 in my GoogleChrome browser console, it evaluates to 123. How does JavaScript interpret the : symbol in this scenario? ...

The jQuery functions properly offline, but fails to load when connected to the

I am encountering an issue with the following script: <script type="text/javascript"> $.getJSON("http://api.twitter.com/1/statuses/user_timeline/koawatea.json?count=1&include_rts=1&callback=?", function(data) { $("#headertweet") ...

Rotating the camera around the origin in Three.js

Hey, I'm having some trouble with what I thought would be a simple task. I have a group of objects at the origin, and I'm trying to rotate a camera around them while always facing the origin. According to the documentation, this code should work: ...