ter

Five Interesting Ways to Use Array.reduce() (And One Boring Way)

Chris Ferdinandi turns the heat down low and lets the sauce reduce while we take a look at how to add spice to our source with a sprinkling of Array.reduce(). Just a little ingenuity with the humblest of functions.


Of all the modern array methods, the one I had the hardest time wrapping my head around was Array.reduce().

On the surface, it seems like a simple, boring method that doesn’t do much. But below its humble exterior, Array.reduce() is actually a powerful, flexible addition to your developer toolkit.

Today, we’re going to look at some cool things you can do with Array.reduce().

How Array.reduce() works

Most of the modern array methods return a new array. The Array.reduce() method is a bit more flexible. It can return anything. Its purpose is to take an array and condense its content into a single value.

That value can be a number, a string, or even an object or new array. That’s the part that’s always tripped me up – I didn’t realize just how flexible it is!

The syntax

The Array.reduce() accepts two arguments: a callback method to run against each item in the array, and a starting value.

The callback also accepts two arguments: the accumulator, which is the current combined value, and the current item in the loop. Whatever you return is used as the accumulator for the next item in the loop. On the very first loop, that starting value is used instead.

var myNewArray = [].reduce(function (accumulator, current) {
  return accumulator;
}, starting);

Let’s look at some examples to make this all tangible.

1. Adding numbers together

Let’s say you had an array of numbers that you wanted to add together. Using Array.forEach(), you might do something like this:

var total = 0;

[1, 2, 3].forEach(function (num) {
  total += num;
});

This is the cliche example for using Array.reduce(). I find the word accumulator confusing, so in this example, I’m calling it sum, because that’s what it is.

var total = [1, 2, 3].reduce(function (sum, current) {
  return sum + current;
}, 0);

Here, we pass in 0 as our starting value.

In the callback, we add the current value to the sum, which has our starting value of 0 on the first loop, then 1 (the starting value of 0 plus the item value of 1), then 3 (the sum value of 1 plus the item value of 2), and so on.

Here’s a demo.

2. Combining multiple array methods into Array.map() and Array.filter() into a single step

Imagine you had an array of wizards at Hogwarts.

var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'
  }
];

You want to create a new array that contains just the names of wizards who are in Hufflepuff. One way you could do that is by using the Array.filter() method to get back just wizards whose house property is Hufflepuff. Then, you’d use the Array.map() method to create a new array containing just the name property for the remaining wizards.

// Get the names of the wizards in Hufflepuff
var hufflepuff = wizards.filter(function (wizard) {
  return wizard.house === 'Hufflepuff';
}).map(function (wizard) {
  return wizard.name;
});

With the Array.reduce() method, we can get the same array in a single pass, improving our performance. You pass in an empty array ([]) as the starting value. On each pass, you check to see if the wizard.house is Hufflepuff. If it is, you push it to the newArr (our accumulator in this example). If not, you do nothing.

Either way, you return the newArr to become the accumulator on the next pass.

// Get the names of the wizards in Hufflepuff
var hufflepuff = wizards.reduce(function (newArr, wizard) {
  if (wizard.house === 'Hufflepuff') {
    newArr.push(wizard.name);
  }
  return newArr;
}, []);

Here’s another demo.

3. Creating markup from an array

What if, instead of creating an array of names, we wanted to create an unordered list of wizards in Hufflepuff? Instead of passing an empty array into Array.reduce() as our starting value, we’ll pass in an empty string ('') and call it html.

If the wizard.house equals Hufflepuff, we’ll concatenate our html string with the wizard.name wrapped in an opening and closing list item (li). Then, we’ll return the html to become the accumulator on the next loop.

// Create a list of wizards in Hufflepuff
var hufflepuffList = wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, '');

Add an opening and closing unordered list element before and after Array.reduce(), and you’re ready to inject your markup string into the DOM.

// Create a list of wizards in Hufflepuff
var hufflepuffList = '<ul>' + wizards.reduce(function (html, wizard) {
  if (wizard.house === 'Hufflepuff') {
    html += '<li>' + wizard.name + '</li>';
  }
  return html;
}, '') + '</ul>';

See it in action here.

4. Grouping similar items in an array together

The lodash library has a groupBy() method takes a collection of items as an array and groups them together into an object based on some criteria.

Let’s say you want an array of numbers.

If you wanted to group all of the items in numbers together based on their integer value, you would do this with lodash.

var numbers = [6.1, 4.2, 6.3];

// returns {'4': [4.2], '6': [6.1, 6.3]}
_.groupBy(numbers, Math.floor);

If you had an array of words, and you wanted to group the items in words by their length, you would do this.

var words = ['one', 'two', 'three'];

// returns {'3': ['one', 'two'], '5': ['three']}
_.groupBy(words, 'length');

Creating a groupBy() function with Array.reduce()

You can recreate that same functionality using the Array.reduce() method.

We’ll create a helper function, groupBy(), that accepts the array and criteria to sort by as arguments. Inside groupBy(), we’ll run Array.reduce() on our array, passing in an empty object ({}) as our starting point, and return the result.

var groupBy = function (arr, criteria) {
  return arr.reduce(function (obj, item) {
    // Some code will go here...
  }, {});
};

Inside the Array.reduce() callback function, we’ll check to see if the criteria is a function, or a property of the item. Then we’ll get its value from the current item.

If there’s no property in the obj with that value yet, we’ll create it and assign an empty array as its value. Finally, we’ll push the item to that key, and return the object as the accumulator for the next loop.

var groupBy = function (arr, criteria) {
  return arr.reduce(function (obj, item) {

    // Check if the criteria is a function to run on the item or a property of it
    var key = typeof criteria === 'function' ? criteria(item) : item[criteria];

    // If the key doesn't exist yet, create it
    if (!obj.hasOwnProperty(key)) {
      obj[key] = [];
    }

    // Push the value to the object
    obj[key].push(item);

    // Return the object to the next item in the loop
    return obj;

  }, {});
};

Here’s a demo of the completed helper function.

Special thanks to Tom Bremer for helping me make some improvements to this one. You can find this helper function and more like it on the Vanilla JS Toolkit.

5. Combining data from two sources into an array

Remember our array of wizards?

var wizards = [
  {
    name: 'Harry Potter',
    house: 'Gryfindor'
  },
  {
    name: 'Cedric Diggory',
    house: 'Hufflepuff'
  },
  {
    name: 'Tonks',
    house: 'Hufflepuff'
  },
  {
    name: 'Ronald Weasley',
    house: 'Gryfindor'
  },
  {
    name: 'Hermione Granger',
    house: 'Gryfindor'
  }
];

What if you had another data set, an object of house points each wizard has earned.

var points = {
  HarryPotter: 500,
  CedricDiggory: 750,
  RonaldWeasley: 100,
  HermioneGranger: 1270
};

Imagine you wanted to combine both sets of data into a single array, with the number of points added to each wizard’s data in the wizards array. How would you do it?

The Array.reduce() method is perfect for this!

var wizardsWithPoints = wizards.reduce(function (arr, wizard) {

  // Get the key for the points object by removing spaces from the wizard's name
  var key = wizard.name.replace(' ', '');

  // If the wizard has points, add them
  // Otherwise, set them to 0
  if (points[key]) {
    wizard.points = points[key];
  } else {
    wizard.points = 0;
  }

  // Push the wizard object to the new array
  arr.push(wizard);

  // Return the array
  return arr;

}, []);

Here’s a demo combining data from two sources into an array.

6. Combining data from two sources into an object

What if you instead wanted to combine the two data sources into an object, where each wizard’s name was the key, and their house and points were properties? Again, the Array.reduce() method is perfect for this.

var wizardsAsAnObject = wizards.reduce(function (obj, wizard) {

  // Get the key for the points object by removing spaces from the wizard's name
  var key = wizard.name.replace(' ', '');

  // If the wizard has points, add them
  // Otherwise, set them to 0
  if (points[key]) {
    wizard.points = points[key];
  } else {
    wizard.points = 0;
  }

  // Remove the name property
  delete wizard.name;

  // Add wizard data to the new object
  obj[key] = wizard;

  // Return the array
  return obj;

}, {});

Here’s a demo combining two data sets into an object.

Should you use Array.reduce() more?

The Array.reduce() method has gone from being something I thought was pointless to my favorite JavaScript method. So, should you use it? And when?

The Array.reduce() method has fantastic browser support. It works in all modern browsers, and IE9 and above. It’s been supported in mobile browsers for a long time, too. If you need to go back even further than that, you can add a polyfill to push support back to IE6.

The biggest complaint you can make about Array.reduce() is that it’s confusing for people who have never encountered it before. Combining Array.filter() with Array.map() is slower to run and involves extra steps, but it’s easier to read. It’s obvious from the names of the methods what they’re supposed to be doing.

That said, there are times where Array.reduce() makes things that would be complicated more simple rather than more complicated. The groupBy() helper function is a good example.

Ultimately, this is another tool to add to your toolkit. A tool that, if used right, can give you super powers.


About the author

Chris Ferdinandi helps people learn vanilla JavaScript. He believes there’s a simpler, more resilient way to make things for the web.

Chris is the author of the Vanilla JS Pocket Guide series, creator of the Vanilla JS Academy training program, and host of the Vanilla JS Podcast. His developer tips newsletter is read by thousands of developers each weekday.

He’s taught developers at organizations like Chobani and the Boston Globe, and his JavaScript plugins have been used used by Apple and Harvard Business School. Chris Coyier, the founder of CSS-Tricks and CodePen, has described his writing as “infinitely quote-worthy.”

Chris loves pirates, puppies, and Pixar movies, and lives near horse farms in rural Massachusetts. He runs Go Make Things with Bailey Puppy, a lab-mix from Tennessee.

More articles by Chris




ter

Usability and Security; Better Together

Divya Sasidharan calls into question the trade-offs often made between security and usability. Does a secure interface by necessity need to be hard to use? Or is it the choice we make based on years of habit? Snow has fallen, snow on snow.


Security is often synonymous with poor usability. We assume that in order for something to be secure, it needs to by default appear impenetrable to disincentivize potential bad actors. While this premise is true in many instances like in the security of a bank, it relies on a fundamental assumption: that there is no room for choice.

With the option to choose, a user almost inevitably picks a more usable system or adapts how they interact with it regardless of how insecure it may be. In the context of the web, passwords are a prime example of such behavior. Though passwords were implemented as a way to drastically reduce the risk of attack, they proved to be marginally effective. In the name of convenience, complex, more secure passwords were shirked in favor of easy to remember ones, and passwords were liberally reused across accounts. This example clearly illustrates that usability and security are not mutually exclusive. Rather, security depends on usability, and it is imperative to get user buy-in in order to properly secure our applications.

Security and Usability; a tale of broken trust

At its core, security is about fostering trust. In addition to protecting user accounts from malicious attacks, security protocols provide users with the peace of mind that their accounts and personal information is safe. Ironically, that peace of mind is incumbent on users using the security protocols in the first place, which further relies on them accepting that security is needed. With the increased frequency of cyber security threats and data breaches over the last couple of years, users have grown to be less trusting of security experts and their measures. Security experts have equally become less trusting of users, and see them as the “the weakest link in the chain”. This has led to more cumbersome security practices such as mandatory 2FA and constant re-login flows which bottlenecks users from accomplishing essential tasks. Because of this break down in trust, there is a natural inclination to shortcut security altogether.

Build a culture of trust not fear

Building trust among users requires empowering them to believe that their individual actions have a larger impact on the security of the overall organization. If a user understands that their behavior can put critical resources of an organization at risk, they will more likely behave with security in mind. For this to work, nuance is key. Deeming that every resource needs a similarly high number of checks and balances diminishes how users perceive security and adds unnecessary bottlenecks to user workflows.

In order to lay the foundation for good security, it’s worth noting that risk analysis is the bedrock of security design. Instead of blindly implementing standard security measures recommended by the experts, a better approach is to tailor security protocols to meet specific use cases and adapt as much as possible to user workflows. Here are some examples of how to do just that:

Risk based authentication

Risk based authentication is a powerful way to perform a holistic assessment of the threats facing an organization. Risks occur at the intersection of vulnerability and threat. A high risk account is vulnerable and faces the very real threat of a potential breach. Generally, risk based authentication is about calculating a risk score associated with accounts and determining the proper approach to securing it. It takes into account a combination of the likelihood that that risk will materialize and the impact on the organization should the risk come to pass. With this system, an organization can easily adapt access to resources depending on how critical they are to the business; for instance, internal documentation may not warrant 2FA, while accessing business and financial records may.

Dynamically adaptive auth

Similar to risk based auth, dynamically adaptive auth adjusts to the current situation. Security can be strengthened and slackened as warranted, depending on how risky the access point is. A user accessing an account from a trusted device in a known location may be deemed low risk and therefore not in need of extra security layers. Likewise, a user exhibiting predictive patterns of use should be granted quick and easy access to resources. The ability to adapt authentication based on the most recent security profile of a user significantly improves the experience by reducing unnecessary friction.

Conclusion

Historically, security failed to take the user experience into account, putting the onus of securing accounts solely on users. Considering the fate of password security, we can neither rely on users nor stringent security mechanisms to keep our accounts safe. Instead, we should aim for security measures that give users the freedom to bypass them as needed while still protecting our accounts from attack. The fate of secure systems lies in the understanding that security is a process that must constantly adapt to face the shifting landscape of user behavior and potential threats.


About the author

Divya is a web developer who is passionate about open source and the web. She is currently a developer experience engineer at Netlify, and believes that there is a better workflow for building and deploying sites that doesn’t require a server—ask her about the JAMstack. You will most likely find her in the sunniest spot in the room with a cup of tea in hand.

More articles by Divya




ter

Cigarette taxes and smoking among sexual minority adults [electronic resource] / Christopher Carpenter, Dario Sansone

Cambridge, Mass. : National Bureau of Economic Research, 2020




ter

DUTRA GROUP v. BATTERTON, CHRISTOPHER. Decided 06/24/2019




ter

Leadership decapitation: strategic targeting of terrorist organizations / Jenna Jordan

Dewey Library - HV6431.J674 2019




ter

Power to the people: how open technological innovation is arming tomorrow's terrorists / Audrey Kurth Cronin

Dewey Library - U39.C76 2020




ter

Also serving time: Canada's provincial and territorial correctional officers / Rosemary Ricciardelli

Dewey Library - HV9506.R53 2019




ter

Democracy Incorporated: Managed Democracy and the Specter of Inverted Totalitarianism - New Edition / Sheldon S. Wolin

Online Resource




ter

The modern Republican Party in Florida / Peter Dunbar and Mike Haridopolos

Dewey Library - JK2358.F5 D86 2019




ter

Faithful fighters: identity and power in the British Indian Army / Kate Imy

Dewey Library - UA668.I49 2019




ter

Shadows of doubt: stereotypes, crime, and the pursuit of justice / Brendan O'Flaherty, Rajiv Sethi

Online Resource




ter

Monsters to destroy: understanding the "War on Terror" / Navin A. Bapat

Dewey Library - HV6432.B364 2019




ter

Extreme reactions: radical right mobilization in Eastern Europe / Lenka Bustikova, Arizona State University

Dewey Library - JC573.2.E852 B88 2020




ter

Territorial sovereignty: a philosophical exploration / Anna Stilz

Dewey Library - JC327.S79 2019




ter

Assessment of the in-house laboratory independent research at the Army's Research, Development, and Engineering Centers / Army Research Program Review and Analysis Committee, Division on Engineering and Physical Sciences

Online Resource




ter

Trump and his generals: the cost of chaos / Peter Bergen

Dewey Library - UA23.B415 2019




ter

Managing interdependencies in federal systems: intergovernmental councils and the making of public policy / Johanna Schnabel

Online Resource




ter

We are indivisible: a blueprint for democracy after Trump / Leah Greenberg and Ezra Levin ; [foreword by Marielena Hincapié]

Dewey Library - JC423.G74 2019




ter

Militarization: a reader / Roberto J. González, Hugh Gusterson, Gustaaf Houtman, editors ; in collaboration with Catherine Besteman, Andrew Bickford, Catherine Lutz, Katherine T. McCaffrey, Austin Miller, David H. Price, David Vine

Dewey Library - U21.2.M558 2019




ter

Citizenship: what everyone needs to know / Peter J. Spiro

Dewey Library - JF801.S694 2020




ter

Soft target protection: theoretical basis and practical measures / edited by Ladislav Hofreiter, Viacheslav Berezutskyi, Lucia Figuli and Zuzana Zvaková

Online Resource




ter

The politics of war powers: the theory and history of Presidential unilateralism / Sarah Burns

Dewey Library - JK560.B87 2019




ter

Beyond smart and connected governments: sensors and the internet of things in the public sector / J. Ramon Gil-Garcia, Theresa A. Pardo, Mila Gasco-Hernandez, editors

Online Resource




ter

The end of European security institutions: the EU's common foreign and security policy and NATO after Brexit / Benjamin Zyla

Online Resource




ter

International empirical studies on religion and socioeconomic human rights Hans-Georg Ziebertz, editor

Online Resource




ter

How to be a dictator: the cult of personality in the twentieth century / Frank Dikötter

Dewey Library - JC495.D55 2019




ter

America's use of terror: from Colonial times to the A-bomb / Stephen Huggins

Dewey Library - HV6432.H8244 2019




ter

Why veterans run: military service in American presidential elections, 1789-2016 / Jeremy M. Teigen

Dewey Library - JK524.T36 2018




ter

Exploring Patterns of Behaviour in Violent Jihadist Terrorists: an analysis of six significant terrorist conspiracies in the UK.

Online Resource




ter

The American lab: an insider's history of the Lawrence Livermore National Laboratory / C. Bruce Tarter

Hayden Library - U394.L58 T37 2018




ter

Surviving state terror: women's testimonies of repression and resistance in Argentina / Barbara Sutton

Dewey Library - HV6433.A7 S88 2018




ter

Proceeding of the VI International Ship Design and Naval Engineering Congress (CIDIN) and XXVI Pan-American Congress of Naval Engineering, Maritime Transportation and Port Engineering (COPINAVAL) / Vice Admiral Jorge Enrique Carreño Moreno, Adan Veg

Online Resource




ter

Genealogies of terrorism: revolution, state violence, empire / Verena Erlenbusch-Anderson

Dewey Library - HV6431.E744 2018




ter

Suspect communities: anti-Muslim racism and the domestic war on terror / Nicole Nguyen

Dewey Library - HV6432.N555 2019




ter

Secret empires: how the American political class hides corruption and enriches family and friends / Peter Schweizer

Dewey Library - JK2249.S349 2018




ter

Perilous futures: on Carl Schmitt's late writings / Peter Uwe Hohendahl

Dewey Library - JC263.S34 H62 2018




ter

The anti-black city: police terror and black urban life in Brazil / Jaime Amparo Alves

Dewey Library - HV8183.A48 2018




ter

Back to America: identity, political culture, and the Tea Party movement / William H. Westermeyer

Dewey Library - JK2391.T43 W48 2019




ter

Gunslinging justice: the American culture of gun violence in Westerns and the law / Justin A. Joyce

Dewey Library - HV7436.J69 2018




ter

Naming violence: a critical theory of genocide, torture, and terrorism / Mathias Thaler

Dewey Library - JC328.6.T54 2018




ter

Intelligence and state surveillance in modern societies: an international perspective / by Frederic Lemieux

Dewey Library - JF1525.I6 L46 2019




ter

I am the people: reflections on popular sovereignty today / Partha Chatterjee

Dewey Library - JC423.C366 2020




ter

The class of '74: Congress after Watergate and the roots of partisanship / John A. Lawrence

Dewey Library - JK1059 94th.L39 2018




ter

The smile of the human bomb: new perspectives on suicide terrorism / Gideon Aran ; translated by Jeffrey Green

Dewey Library - HV6433.I75 A735 2018




ter

Citizenship as a regime: Canadian and international perspectives / edited by Mireille Paquet, Nora Nagels, and Aude-Claire Fourot

Dewey Library - JF801.C58 2018




ter

A place outside the law: forgotten voices from Guantanamo / Peter Jan Honigsberg

Dewey Library - HV6432.H67 2019




ter

Security and terror: American culture and the long history of colonial modernity / Eli Jelly-Schapiro

Dewey Library - HV6432.J445 2018




ter

Pork barrel politics: how government spending determines elections in a polarized era / Andrew H. Sidman

Dewey Library - JK1976.S58 2019




ter

False alarm: the truth about political mistruths in the Trump era / Ethan Porter, Thomas J. Wood

Dewey Library - JK1726.P67 2019




ter

Hacking diversity: the politics of inclusion in open technology cultures / by Christina Dunbar-Hester

Dewey Library - HV6773.D855 2020