Reduce() questions

Hello! I want to add the values up in an array of objects, where the object keys differ, as in,

var foo = [{a:1},{b:2},{c:3}];

I know how to aggregate/reduce when keys are the same, i.e,

var foo = [{a:1},{a:2},{a:3}];
foo.reduce((a,c => a + c.a,0) // 6

I have tried the following,

var foo = [{a:1},{b:2},{c:3}];
foo.reduce((acc,cur) =>{
  acc.total += cur[1];
  return acc;
},{total: 0})

But the result is NaN. Can you explain my error/help? Thanks.

Right so cur is an object, and I want to get at the value of the object but the key changes, so I can’t just call all the values by a single key…and that’s where I’m stuck :frowning:

For cur[1] to work, there would have to be a property with the key 1 on the object, so that can’t work.

So this will work:

Object.values(curr)[0]

So you are getting an array containing the values of the object, and just picking the first one (I am assuming all your objects have a single key).

Note this is incredibly fragile. This is ok for a toy example, but in reality, if your data is a list of objects, and you don’t know the keys for the values you want from those objects, then your data is probably gibberish and unusable. An object is a keyed map of data: if you have no idea what that map looks like then that’s a problem

2 Likes

Thanks for that Dan.
I’m trying to work my way up to a more complicated application of reduce I came across in the ‘Cash register challenge’ that looks like this,

 var register = cid.reduce(function(acc, curr) {
    acc.total += curr[1];
    acc[curr[0]] = curr[1];
    return acc;
  }, { total: 0 });

This code sums up the dollar values in the cid object, passed as an argument, but I don’t understand how, so I am trying to build up my comprehension with simpler exercises like

var foo = [{a:1},{b:2},{c:3}]

But I am totally flailing.

Hmmm. It’s all blurry?

Ah right, this makes more sense given the challenge. The question then is: why are your elements in an object?

The challenge gives you them in a form that’s easy to reduce (an array of two-element arrays - a map). At no point should you need to put the actual change in an object, particularly as the challenge expects the same structure as the input for the change key on the output.

1 Like

Oh cool. Ok that gives me a toe-hold, thank you very much. So the first reduce extracts the values from each object, puts them into an array, and the second reduce then acts on a simple array to add up the values…brilliant.

2 Likes

Well that’s true, I kind of got away from the original problem and went down a reduce rabbit hole. Then I started making myself a reduce cheat sheet and got stumped by data structured as

var foo = [{a:1},{b:2},{c:3}];

Thanks for bearing with me.

1 Like

So that data structure isn’t really a reasonable data structure, so it’s likely not something you need to worry about too much. The reason it’s not reasonable is easier to understand if you think about how you store data.

  1. if you have an object {a: 1, b: 2, c: 3}, that’s reasonable. It’s like one instance of a thing - like a user: { name: 'Foo', age: 25 }. You wouldn’t reduce etc over it because it’s an object, you just look up what you want on it (user.name).
  2. if you have a map of data, that’s reasonable as well. By map, I mean something that looks like this: [[key, value],[key, value]] in JS*.
  3. if you have a list of objects, and those objects all have the same type, the same shape, then that’s reasonable. It’s a collection of things of a type - users for example. You would totally map/reduce/etc over that - get all the ages of users, get the average age of users, whatever.
  4. If you have a list of values, that’s reasonable: it’s just a plain list of values from somewhere.

What you’ve ended up at, how would that be stored? It can’t have come out of a relational database because 3 is what you get out when you want a list of items: if you ask for a collection of users, you don’t get {name: 'Foo' } as the first item in the collection, then {age: 21} for the second item in the collection.

It doesn’t quite make sense, a list of objects with unknown keys, because the end result is that you’re guessing things, and computers aren’t very good at doing that.

* What you have in the challenge is a map, and it wouldn’t be uncommon to have unknown keys. But with a map you’re likely to have a known type/format of key or value or both. For example a web cache is normally stored with the url as the key and the page HTML as the value.

1 Like

That really makes perfect sense. I can see now that data structured as

[{a: 1},{b:2}];

wouldn’t have much real world application…I kind of got carried away trying to reduce everything in sight. Thanks for pointing that out.