1

I have an array of objects such like this one:

0: {Id: "D", Inmueble: "00000021", Valexcep: 2}
1: {Id: "D", Inmueble: "00000021", Valexcep: 2}
2: {Id: "D", Inmueble: "00000023", Valexcep: 1}
3: {Id: "D", Inmueble: "00000023", Valexcep: 2}
4: {Id: "D", Inmueble: "00000024", Valexcep: 3}
5: {Id: "D", Inmueble: "00000168", Valexcep: 3}

I need to sum "Valexcep" values from those objects that have same "Inmueble" value, such has the first two of the array

I need to be able to get this output

0: {Id: "D", Inmueble: "00000021", Valexcep: 4}
2: {Id: "D", Inmueble: "00000023", Valexcep: 3}
4: {Id: "D", Inmueble: "00000024", Valexcep: 3}
5: {Id: "D", Inmueble: "00000168", Valexcep: 3}

Here's the code I have so far

    var discount = 0;
    var inmueble = "";


    $.each(array, function(i, val) {
        if (val.Id == 'D') {
            discount += val.Valexcep;
            inmueble = val.Inmueble;
            var newObj = {
                id: val.Id,
                Inmueble: val.Inmueble
                Valexcep: val.Valexcep; 
            }               
            array.push(newObj)              
        }

    });

But is not working as expected,

any idea how to figure this out?

Afsanefda
  • 3,069
  • 6
  • 36
  • 76
victoriana
  • 69
  • 5
  • Please elaborate: *how* does the output differ from what you expect? – Scott Hunter Sep 25 '19 at 17:36
  • you can map each distinct Inmueble value to an object, if one exist then increment it's Valexcep, else create a new object. but why are you using jquery for this. – Chris Li Sep 25 '19 at 17:45

2 Answers2

2

You could reduce the array by taking an array as result set and look if an object with the same Inmueble exists, then update Valexcep, otherwise push a new object to the result set.

var data = [{ Id: "D", Inmueble: "00000021", Valexcep: 2 }, { Id: "D", Inmueble: "00000021", Valexcep: 2 }, { Id: "D", Inmueble: "00000023", Valexcep: 1 }, { Id: "D", Inmueble: "00000023", Valexcep: 2 }, { Id: "D", Inmueble: "00000024", Valexcep: 3 }, { Id: "D", Inmueble: "00000168", Valexcep: 3 }],
    result = data.reduce((r, { Id, Inmueble, Valexcep }) => {
        var temp = r.find(o => o.Inmueble === Inmueble);
        if (temp) {
            temp.Valexcep += Valexcep;
        } else {
            r.push({ Id, Inmueble, Valexcep });
        }
        return r;
    }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

A grouping with a Map.

var data = [{ Id: "D", Inmueble: "00000021", Valexcep: 2 }, { Id: "D", Inmueble: "00000021", Valexcep: 2 }, { Id: "D", Inmueble: "00000023", Valexcep: 1 }, { Id: "D", Inmueble: "00000023", Valexcep: 2 }, { Id: "D", Inmueble: "00000024", Valexcep: 3 }, { Id: "D", Inmueble: "00000168", Valexcep: 3 }],
    result = Array.from(data
        .reduce((m, { Id, Inmueble, Valexcep }) => m.set(
            Inmueble,
            { Id, Inmueble, Valexcep: (m.has(Inmueble) ? m.get(Inmueble).Valexcep : 0) + Valexcep }
        ), new Map)
        .values()
    );

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • damn, you are fast !! – que1326 Sep 25 '19 at 17:55
  • you're FFF genius! – victoriana Sep 25 '19 at 17:59
  • I would argue for using an object to look up and store values and then converting to an array at the end. As it stands, the runtime of this is worst-case O(n^2) because of the `r.find` inside the `r.reduce`; if you use an object to do constant-time lookups and storage, then it's just O(2n) = O(n). (Or a Map for O(log n) would also still be better.) – IceMetalPunk Sep 25 '19 at 18:30
  • @IceMetalPunk, right, that is another approach. maybe the second one is better. – Nina Scholz Sep 25 '19 at 18:42
0

From what I understand, you first need to group your element by Inmueble and then reduce them to get their totals. Ceasar Bautista has a pretty good method to group by a property, and we will use it in order to create a new "grouped" array. :

//https://stackoverflow.com/a/34890276/5784924
function groupBy (xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

let input = [
  {Id: "D", Inmueble: "00000021", Valexcep: 2},
  {Id: "D", Inmueble: "00000021", Valexcep: 2},
  {Id: "D", Inmueble: "00000023", Valexcep: 1},
  {Id: "D", Inmueble: "00000023", Valexcep: 2},
  {Id: "D", Inmueble: "00000024", Valexcep: 3},
  {Id: "D", Inmueble: "00000168", Valexcep: 3}
]

// we first group the values by Inmueble
let grouppedValues = groupBy(input, 'Inmueble');

// the functions returns an object with the Inmueble as key, so we parse each key.
// we use reduce because it's easier to returns an object. We could use a simple forEach aswell.
let output = Object.keys(grouppedValues).reduce(function(collector, value) {
  // get the current value from the key we got.
  let currentGrouppedValue = grouppedValues[value];
  
  // for each groupped element, we add the Valexcep value
  let total = 0
  grouppedValues[value].forEach((data) => { 
    total += data.Valexcep;
  });
  
  // the collector is what is return, so we construct a new object with the element we need.
  // in our case, we can use the Id and Inmueble from the first group element since it will
  // always be the same.
  collector.push({
    Id: currentGrouppedValue[0].Id,
    Inmueble: currentGrouppedValue[0].Inmueble,
    Valexcep: total
  });
  
  // we return the updated collector.
  return collector;
}, []);


// do whatever you like with the output.
console.log(output);
Nicolas
  • 8,077
  • 4
  • 21
  • 51