6
var myArray = [
  {"Emiten_ID":'SMBR',"Lot":500,"Price":2500},     
  {"Emiten_ID":'SMBR',"Lot":300,"Price":2200},     
  {"Emiten_ID":'ELSA',"Lot":500,"Price":1000},
  {"Emiten_ID":'SMBR',"Lot":100,"Price":3000},     
  {"Emiten_ID":'BI',"Lot":300,"Price":500},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":1300},
  {"Emiten_ID":'BTB',"Lot":700,"Price":2900},     
  {"Emiten_ID":'BI',"Lot":150,"Price":200},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":600},
];

i want result like this, where i get sum from lot and max value from price

var Result= [
  {"Emiten_ID":'ELSA',"Lot":500,"Price":1000},
  {"Emiten_ID":'SMBR',"Lot":900,"Price":3000},     
  {"Emiten_ID":'BI',"Lot":450,"Price":500},     
  {"Emiten_ID":'BTB',"Lot":700,"Price":2900},     
  {"Emiten_ID":'AAI',"Lot":400,"Price":1300},
];
1
  • 2
    I don't see any JavaScript (other than the problem and a desired result), what have you tried with JavaScript? Please provide a minimal reproducible example. Commented Sep 20, 2016 at 5:46

8 Answers 8

3

You could use Array#forEach and an object as hash table and group it by Emiten_ID.

var myArray = [{ "Emiten_ID": 'SMBR', "Lot": 500, "Price": 2500 }, { "Emiten_ID": 'SMBR', "Lot": 300, "Price": 2200 }, { "Emiten_ID": 'ELSA', "Lot": 500, "Price": 1000 }, { "Emiten_ID": 'SMBR', "Lot": 100, "Price": 3000 }, { "Emiten_ID": 'BI', "Lot": 300, "Price": 500 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 1300 }, { "Emiten_ID": 'BTB', "Lot": 700, "Price": 2900 }, { "Emiten_ID": 'BI', "Lot": 150, "Price": 200 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 600 }, ],
    result = [];

myArray.forEach(function (a) {
    if (!this[a.Emiten_ID]) {
        this[a.Emiten_ID] = { Emiten_ID: a.Emiten_ID, Lot: 0, Price: 0 };
        result.push(this[a.Emiten_ID]);
    }
    this[a.Emiten_ID].Lot += a.Lot;
    this[a.Emiten_ID].Price = Math.max(this[a.Emiten_ID].Price, a.Price);
}, Object.create(null));

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

ES6 with a closure of hash without use of this.

var myArray = [{ "Emiten_ID": 'SMBR', "Lot": 500, "Price": 2500 }, { "Emiten_ID": 'SMBR', "Lot": 300, "Price": 2200 }, { "Emiten_ID": 'ELSA', "Lot": 500, "Price": 1000 }, { "Emiten_ID": 'SMBR', "Lot": 100, "Price": 3000 }, { "Emiten_ID": 'BI', "Lot": 300, "Price": 500 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 1300 }, { "Emiten_ID": 'BTB', "Lot": 700, "Price": 2900 }, { "Emiten_ID": 'BI', "Lot": 150, "Price": 200 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 600 }, ],
    result = [];

myArray.forEach((hash => a => {
    if (!hash[a.Emiten_ID]) {
        hash[a.Emiten_ID] = { Emiten_ID: a.Emiten_ID, Lot: 0, Price: 0 };
        result.push(hash[a.Emiten_ID]);
    }
    hash[a.Emiten_ID].Lot += a.Lot;
    hash[a.Emiten_ID].Price = Math.max(hash[a.Emiten_ID].Price, a.Price);
})(Object.create(null)));

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

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

5 Comments

What does this refer to in this answer?
it refers to thisArg: Object.create(null).
Hi @NinaScholz. I know you love using the thisArg parameter to forEach etc. as a sort of free context variable, but based on the comment above I guess it's not only me who finds it a bit counter-intuitive.
Cool, makes it functionally equivalent to temp in my answer. I learned something new today :-).
@torazaburo, would a closure fits better?
3

Using Map class available in ECMAScript 2015 (or polyfill):

var myArray = [{ "Emiten_ID": 'SMBR', "Lot": 500, "Price": 2500 }, { "Emiten_ID": 'SMBR', "Lot": 300, "Price": 2200 }, { "Emiten_ID": 'ELSA', "Lot": 500, "Price": 1000 }, { "Emiten_ID": 'SMBR', "Lot": 100, "Price": 3000 }, { "Emiten_ID": 'BI', "Lot": 300, "Price": 500 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 1300 }, { "Emiten_ID": 'BTB', "Lot": 700, "Price": 2900 }, { "Emiten_ID": 'BI', "Lot": 150, "Price": 200 }, { "Emiten_ID": 'AAI', "Lot": 200, "Price": 600 }, ]

var temp = new Map();

for (var item of myArray) {
    var e = temp.get(item.Emiten_ID)
    if (e) {
        e.Lot += item.Lot;
        e.Price = Math.max( e.Price, item.Price );
    } else {
        temp.set( item.Emiten_ID, 
            { Emiten_ID: item.Emiten_ID, Lot:item.Lot, Price:item.Price })
    }
}

var result = Array.from(temp.values());

console.log(result)

4 Comments

I think it's because you're adding the values to the map as properties, rather than entries. You should be doing map.set, right?
Your right @torazaburo, that works. I've updated my answer.
The first line in the for loop should read temp.get, right?
I was wondering about that. Seems to work in node.js without using temp.get, but it seems like good style to use the symmetrical approaches. Updated.
2

You can use linq.js library:

var myArray = [
  {"Emiten_ID":'SMBR',"Lot":500,"Price":2500},     
  {"Emiten_ID":'SMBR',"Lot":300,"Price":2200},     
  {"Emiten_ID":'ELSA',"Lot":500,"Price":1000},
  {"Emiten_ID":'SMBR',"Lot":100,"Price":3000},     
  {"Emiten_ID":'BI',"Lot":300,"Price":500},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":1300},
  {"Emiten_ID":'BTB',"Lot":700,"Price":2900},     
  {"Emiten_ID":'BI',"Lot":150,"Price":200},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":600},
];
var answer = Enumerable.From(myArray).GroupBy("x => x.Emiten_ID", "x => {Lot: x.Lot, Price: x.Price}").Select("x => {Emiten_ID:x.Key(), Lot:x.Sum(y=>y.Lot), Price:x.Max(y=>y.Price)}").ToArray();
answer.forEach(x => console.log(x));
<script data-require="[email protected]" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
<script data-require="[email protected]+2" data-semver="2.2.0+2" src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
<script data-require="[email protected]+2" data-semver="2.2.0+2" src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/jquery.linq.js"></script>

Comments

1

this is long way to this, hope there is simpler way do this.

var myArray = [
  {"Emiten_ID":'SMBR',"Lot":500,"Price":2500},     
  {"Emiten_ID":'SMBR',"Lot":300,"Price":2200},     
  {"Emiten_ID":'ELSA',"Lot":500,"Price":1000},
  {"Emiten_ID":'SMBR',"Lot":100,"Price":3000},     
  {"Emiten_ID":'BI',"Lot":300,"Price":500},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":1300},
  {"Emiten_ID":'BTB',"Lot":700,"Price":2900},     
  {"Emiten_ID":'BI',"Lot":150,"Price":200},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":600},
];

var sortedIds = [];
var Result = [];
function sortArray(){

    for(var i = 0; i < myArray.length; i++){
        if(myArray.indexOf(myArray[i].Emiten_ID) < 0){
            sortedIds.push(myArray[i].Emiten_ID);
            Result.push({
                "Emiten_ID" : myArray[i].Emiten_ID,
                "Lot"       : sumLot(myArray[i].Emiten_ID),
                "Price"     : maxPrice(myArray[i].Emiten_ID);
            });


        }
    }   

    //out put
    console.log(Result);
}

function sumLot(id){
    var sum = 0;
    for(var i = 0; i < myArray.length; i++){
        if(myArray[i].Emiten_ID == id){
            sum += myArray[i].lot;
        }
    }   
    return sum;
}

function maxPrice(id){
    var max = 0;
    for(var i = 0; i < myArray.length; i++){
        if(myArray[i].Price > max){
            max = myArray[i].Price;
        }
    }   
    return max;
}

Comments

1

var myArray = [
  {"Emiten_ID":'SMBR',"Lot":500,"Price":2500},     
  {"Emiten_ID":'SMBR',"Lot":300,"Price":2200},     
  {"Emiten_ID":'ELSA',"Lot":500,"Price":1000},
  {"Emiten_ID":'SMBR',"Lot":100,"Price":3000},     
  {"Emiten_ID":'BI',"Lot":300,"Price":500},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":1300},
  {"Emiten_ID":'BTB',"Lot":700,"Price":2900},     
  {"Emiten_ID":'BI',"Lot":150,"Price":200},     
  {"Emiten_ID":'AAI',"Lot":200,"Price":600},
];

myArray = myArray.sort(function(a,b){
	if(a.Emiten_ID > b.Emiten_ID)
		return 1;
	else if(a.Emiten_ID < b.Emiten_ID)
		return -1;
	else{
		return a.Price - b.Price;
	}
});

var result = [myArray[0]];

for(var i = 1 ; i < myArray.length ; i ++){
	var obj = myArray[i];
	var res = result[result.length - 1];
	
	if(obj.Emiten_ID == res.Emiten_ID){
		res.Lot += obj.Lot;
		res.Price = Math.max(res.Price,obj.Price);
	}else{
		result.push(obj);
	}

}

console.log(result);

Comments

1

Solution using lodash:

_.chain(myArray).groupBy('Emiten_ID').map(emiten => ({
  "Emiten_ID":emiten[0]['Emiten_ID'],
  "Lot": _.sumBy(emiten, 'Lot'),
  "Price": _.maxBy(emiten, 'Price')['Price']
})).value()

Comments

1
  • Iterate all the array elements
  • Find the index of each-element from new array
  • If element does not exist, push it in array
  • If element exists, sum the value of Lot and if value of Price is heigher, over-ride the heigher value

var myArray = [{
        "Emiten_ID": 'SMBR',
        "Lot": 500,
        "Price": 2500
    }, {
        "Emiten_ID": 'SMBR',
        "Lot": 300,
        "Price": 2200
    }, {
        "Emiten_ID": 'ELSA',
        "Lot": 500,
        "Price": 1000
    }, {
        "Emiten_ID": 'SMBR',
        "Lot": 100,
        "Price": 3000
    }, {
        "Emiten_ID": 'BI',
        "Lot": 300,
        "Price": 500
    }, {
        "Emiten_ID": 'AAI',
        "Lot": 200,
        "Price": 1300
    }, {
        "Emiten_ID": 'BTB',
        "Lot": 700,
        "Price": 2900
    }, {
        "Emiten_ID": 'BI',
        "Lot": 150,
        "Price": 200
    }, {
        "Emiten_ID": 'AAI',
        "Lot": 200,
        "Price": 600
    }];
    var newArr = [];

    myArray.forEach(function (el) {
        var findIndex = newArr.findIndex(function (item) {
            return item.Emiten_ID === el.Emiten_ID;
        });
        if (findIndex === -1) {
            newArr.push(el);
        } else if (el.Price > newArr[findIndex].Price) {
            newArr[findIndex].Price = el.Price;
            newArr[findIndex].Lot += el.Lot;
        } else {
            newArr[findIndex].Lot += el.Lot;
        }
    });
    console.log(JSON.stringify(newArr, null, 4));

Comments

1

Let's try to decompose this. We'll start by writing a generic utility function which we will call combine, which combines properties on objects using a function specified for each property in a hash called combiners:

function combine(array, combiners) {
  const result = {};
  for (prop of Object.keys(combiners)) {
    result[prop] = combiners[prop](...array.map(elt => elt[prop]));
  }
  return result;
}

Example of using this:

combine(
  [{a: 1, b: 10}, {a: 42, b: 80}],
  {a: sum, b: Math.max}
)

which will result in

{a: 43, b: 80}

Of course, to make this work, we'll have to define sum:

function sum(...vals) { return vals.reduce(add); }

where add is just

function add(a, b) { return a + b; }

Next, we will group the input by the Emiten_ID property. You could use Underscore's _.groupBy for this, or write your own (see below).

const groups = _.groupBy(myArray, 'Emiten_ID`);

This will result in something looking like

{ SMBR: [
    { Emiten_ID: 'SMBR', "Lot": 500, "Price": 2500},     
    { Emiten_ID: 'SMBR', "Lot": 300, "Price": 2200}
  ],
  ELSA: [
  ]
}

After doing this prep work, it is pretty easy to get the result, by just mapping each value in groups using our combine utility:

const Result = Object.keys(groups).map(key =>
  combine(
    groups[key], 
    {
      Emiten_ID: identity, 
      Lot: sum, 
      Price: Math.max}));

where identity is just

function identity(id) { return id; }

If you'd prefer to abstract away the notion inside combine of mapping object properties, you could use some utility from Underscore again, or write it yourself:

function mapObject(obj, fn) {
  const result = {};

  for (prop of obj) result[prop] = fn(obj[prop], prop);
  return result;
}

Example of using this:

mapObject({a: 2, b: 3}, x => x * x)
// yields {a: 4, b: 9}

Now you can write combine a bit more simply, as

function combine(array, combiners) {
  return mapObject(combiners, function(combiner, prop) {
    return combiner(...array.map(elt => elt[prop]));
  };
}

In case you don't want to use Underscore's _.groupBy, here's a home grown version:

function groupBy(array, prop) {
  var result = {};
  array.forEach(elt => (result[elt[prop]] = result[elt[prop]] || []).push(elt));
  return result;
}

1 Comment

const Result = Object.keys(groups).map(key => return combine( you could skip return.

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.