3

I have an array grouped by different categories and each category have nested more objects with different values (numeric and strings) which i have to reduce (except the strings). Reduce is working fine with numeric values making a sum of them but its overwriting the string values keeping just the last one.

I'm trying to reduce an object/dictionnary by category and fill a table with the sum of the units of each category but don't sum them if the subcategories and names are different.

Here is a demo:

var data = {
  'Category xxxx': [
    {
      units: 1234,
      subcategory: 'wolves',
      name: 'Starks'
    },
    {
      units: 1345354,
      subcategory: 'wolves',
      name: 'Starks'
    },
   {
      units: 666,
      subcategory: 'dragons',
      name: 'Targaryens'
    }
  ], 
  'Category yyyy': [
    {
      units: 7783,
      subcategory: 'lions',
      name: 'Lanisters'
    },
    {
      units: 1267878,
      subcategory: 'spires',
      name: 'Martells'
    }
  ]
}

var test = _.map(data, function (value, key) {
  var returnedData = {
    Category: key,
    units: _(value).reduce(function (memo, metrics) {
      return memo + metrics.units;
    }, 0),
    subcategory: _(value).reduce(function (memo, metrics) {
      return metrics.subcategory;
    }, 0),
    name: _(value).reduce(function (memo, metrics) {
      return metrics.name;
    }, 0),
  };
  return returnedData;
});

console.log(test)
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

The units (integers) are adding up fine but the strings get overwritten by the last iterated string property.

I want to obtain something like this where if the strings are different the integers are not added up.

returnedData = {
  'Category xxxx': [
    {
      units: 1346588,
      chivalry: 'wolves',
      name: 'Starks'
    },
    {
      units: 666,
      subcategory: 'dragons',
      name: 'Targaryens'
    }
  ], 
  'Category yyyy': [
    {
      clicks: 7783,
      subcategory: 'lions',
      name: 'Lanisters'
    },
    {
      clicks: 1267878,
      subcategory: 'spires',
      name: 'Martells'
    }
  ]
}

What is the best way to do it?

5
  • Looks like simple $.each Commented Jun 21, 2016 at 9:51
  • 5
    @Justinas: There's no jquery tag, and even if there were, $.each is so 2008. :-) Array#forEach or possibly Array#reduce would be applicable. Commented Jun 21, 2016 at 9:52
  • @phileras Can you provide an example of the expected results and what you tried? Commented Jun 21, 2016 at 9:54
  • yes @Justinas im trying with reduce, in this case underscore reduce but i will use javascript array.reduce if possible. Commented Jun 21, 2016 at 9:58
  • hi @T.J.Crowder i want the result similar to Nina answer, the array i showed here is a demo in this case the data is really big and i will have to do more subgroups but the idea and result of Nina is appropiated. After that i will need to check performance, but well this is a begging. Thanks :) Commented Jun 21, 2016 at 10:16

2 Answers 2

5

Finally, this proposal uses an object as reference to the items of the result object.

If no result object is available, then it creates a new one with the wanted category. For subcategories it generates an element which is pushed to the result array.

The count is maintained with hash as reference to the elements of result.

var data = { 'Category xxxx': [{ clicks: 1234, subcategory: 'dogs', name: 'jhon doe' }, { clicks: 1345354, subcategory: 'dogs', name: 'jhon doe' }], 'Category yyyy': [{ clicks: 7783, subcategory: 'frogs', name: 'lanisters' }, { clicks: 1267878, subcategory: 'rats', name: 'perry' }] },
    result = {};

Object.keys(data).forEach(function (k) {
    var hash = Object.create(null);
    if (!result[k]) {
        result[k] = [];
    }
    data[k].forEach(function (a) {
        if (!hash[a.subcategory]) {
            hash[a.subcategory] = { clicks: 0, subcategory: a.subcategory, name: a.name };
            result[k].push(hash[a.subcategory]);
        }
        hash[a.subcategory].clicks += a.clicks;
    });
});

console.log(result);

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

17 Comments

Nice one, Nina! Though FWIW I would avoid the (perceived) complexity of using this as a map of category subcategories, presumably we only need to combine entries within an overall category. Was just modifying your original solution with an eye toward editing it in above (you'd done the bulk of the work, after all) when you did your own. FWIW, this is what it was: pastie.org/10885155
@T.J.Crowder, you are right, there is no need for category, just for sub. you solution mulate the original.
i suggest to ask a new question. the comments is not the right place for it.
@mortezaT, maybe it is easier for you to look as this answer of me. ther is a proerty with name 'toString' in arr2. you may perfor the same just with {} instead of Object.reate(null). you get the difference.
@phileras, so out of the blue, its no possible to say where's you problem. may it is easier for you to as a new question and highlight your special problem with dynamic variables (which is kind of tautology ...?).
|
1

I think this could be the answer too.

var data = {
	'Category xxxx': [
	{ units: 1234, subcategory: 'wolves', name: 'Starks' }, 
	{ units: 1345354, subcategory: 'wolves', name: 'Starks' }, 
	{ units: 666, subcategory: 'dragons', name: 'Targaryens' }
	],
	'Category yyyy': [
	{ units: 7783, subcategory: 'lions', name: 'Lanisters' }, 
	{ units: 1267878, subcategory: 'spires', name: 'Martells' }
	]
};

var result = {};

Object.keys(data).forEach(function (key) {
	var hash = {};
	data[key].forEach(function (v, k) {
		isNaN(hash[(k = v.subcategory + v.name)]) ?
			(hash[k] = this.push(v) - 1) :
			(this[hash[k]].units += v.units);
	}, (this[key] = []));
}, result);

console.log(result)

7 Comments

Thanks for your answer @mortezaT it works great too, now im looking and comparing both answers to get the best performance. Also im thinking about to recognize typeoff data properties to create the most generic function as possible because it will manage very different kinds of data. ;)
@phileras this is possible to manage some terms but as Nina mentioned in comment you should ask a new question and describe your terms completely.
new question sent @mortezaT. Sorry if look not very specific about the question but my technical language with JS OO is not so good as i am self taught and more specialized on visual stuff so i have a lack of technical language related to it
@phileras would you give me the link for new question. I'm also a self thought in JS OO.
Sorry @mortezaT the question is deleted because they marked it as duplicated so im reading and searching stuff to try to make it by myself, thank you very much for your help!! :)
|

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.