4

I have an array of objects having a boolean field X. [{..., x: true, y: 3, ...]

I need to aggregate this array, in order to obtain a value, true(or false), if all values of x are correspondingly true(or false), otherwise undefined... and a sum of y's...

is that possible to use the reduce Array function, groupby by underscorejs, or another one for this purpose?

ex:

[
 {a:'titi', x: true,  y: 3}, 
 {a:'toto', x: false, y: 6}
]

result

       {x: undefined, y: 9}
2
  • @georg, that is not just a single operation, but the result is a complex object... Commented Oct 17, 2019 at 15:30
  • 1
    ok, I see, reopen Commented Oct 17, 2019 at 15:32

4 Answers 4

8

this is pretty straight-forward with reduce:

.reduce((a, b) => ({
   x: a.x == b.x ? a.x : undefined,
   y: a.y + b.y
}))

Live example:

var input = [
       {a:'titi', x: true,  y: 3}, 
       {a:'toto', x: false, y: 6}
    ];
    
console.log(input.reduce((a, b) => ({
   x: a.x == b.x ? a.x : undefined,
   y: a.y + b.y
})));

Sign up to request clarification or add additional context in comments.

1 Comment

That's pretty cool, though of course it creates a bunch of unnecessary objects. 99.9% of the time that doesn't matter, though.
3

Although you can shoehorn this into a reduce call (because any array operation can be shoehorned into a reduce), there's no benefit to doing so. Just use a loop:

const result = {x: null, y: 0};
for (const entry of array) {
    if (result.x === null) {
        result.x = entry.x;
    } else if (result.x !== entry.x) {
        result.x = undefined;
    }
    result.y += entry.y;
}

Live Example:

function check(array) {
    const result = {x: null, y: 0};
    for (const entry of array) {
        if (result.x === null) {
            result.x = entry.x;
        } else if (result.x !== entry.x) {
            result.x = undefined;
        }
        result.y += entry.y;
    }
    console.log(result);
}
check([
 {a:'titi', x: true,  y: 3}, 
 {a:'toto', x: false, y: 6}
]);
console.log("---");
check([
 {a:'titi', x: true,  y: 3}, 
 {a:'toto', x: true, y: 6}
]);
console.log("---");
check([
 {a:'titi', x: false,  y: 3}, 
 {a:'toto', x: false, y: 6}
]);
console.log("---");

But again, you can shoehorn that into a reduce if you want by always returning the same object:

const result = array.reduce((obj, entry) => {
    if (obj.x === null) {
        obj.x = entry.x;
    } else if (obj.x !== entry.x) {
        obj.x = undefined;
    }
    obj.y += entry.y;
    return obj;
}, {x: null, y: 0});

Live Example:

function check(array) {
    const result = array.reduce((obj, entry) => {
        if (obj.x === null) {
            obj.x = entry.x;
        } else if (obj.x !== entry.x) {
            obj.x = undefined;
        }
        obj.y += entry.y;
        return obj;
    }, {x: null, y: 0});
    console.log(result);
}
check([
 {a:'titi', x: true,  y: 3}, 
 {a:'toto', x: false, y: 6}
]);
console.log("---");
check([
 {a:'titi', x: true,  y: 3}, 
 {a:'toto', x: true, y: 6}
]);
console.log("---");
check([
 {a:'titi', x: false,  y: 3}, 
 {a:'toto', x: false, y: 6}
]);
console.log("---");

But, if you want a reduce solution and you don't mind creating a bunch of temporary throw-away objects, check out Adassko's answer. Simple and straight-forward, and 99.9% of the time, you don't care about the temporary object creation.

Comments

1

I came up with this solution using reduce. Seems kind of hacky, but it should do the job. While reducing the array it determines if every x-value is equal, afterwards it sets the x-value of the reduced object accordingly.

let reduced = arr.reduce((acc, curr) => {
    acc.x &= acc.x_init === curr.x;
    acc.y += curr.y;
  }, {x_init: arr[0].x, x: true, y: 0});
reduced.x = reduced.x ? reduced.x_init : undefined;
delete reduced.x_init;

Comments

0

thanks @Adassko, my variant was a little bit longer:

[
  {a:'titi', x: false,  y: 3}, 
  {a:'toto', x: false, y: 6}
]
.reduce((a, b, i) => ({
  x : a.x === b.x || i == 0 ? b.x : undefined,
  y : a.y + b.y
}))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.