Search code examples
javascriptarraysunderscore.jscombinationssublist

How to change an array of dictionaries into a list of sublists representing a combinations of two attributes in the array using javascript?


I'd like to change the below array named 'data' into the resulting list of sublists below named 'result'

data = [{'name':'abby','fruit':'apple'},{'name':'abby','fruit':'apple'},{'name':'abby','fruit':'banana'},{'name':'bobby','fruit':'apple'},{'name':'chris','fruit':'banana'}]

Based on this data the following visual can be created (created to help clarify):

Abby has an apple and banana, bobby just has a apple, chris just has a banana

I'd like to represent the array as a list of sublists, where each sublist has three items within it. There should be six sublists to represent every combination of 'name' and 'fruit', as well as the count of that combination. The first item in the sublist should be the name of the person,, second item should the fruit, and the third item should be the count:

As such, I'd like to create the following list of six items:

result = [['abby','apple',2],['bobby','apple',1],['chris','apple',0],['abby','banana',1],['bobby','banana',0],['chris','banana',1]]

The method that I'm currently trying to figure this out is the following:

1) Identify the unique values at 'name' and 'fruit' using underscore.js

var names = _.uniq(_.pluck(data,'name')) 
['abby','bobby','chris']

var names = _.uniq(_.pluck(data,'fruit')) 
fruit = ['apple','banana']

2) Create all combinations of these two lists, which I'm still figuring out how to do in javascript

[['abby','apple'],['bobby','apple'],['chris','apple'],['abby','banana'],['bobby','banana'],['chris','banana']]

3) From this list of combinations, add the count for how many times it's occured in the list to produce the following (also still trying to figure out how to do in javascript)

[['abby','apple',2],['bobby','apple',1],['chris','apple',0],['abby','banana',1],['bobby','banana',0],['chris','banana',1]]

Solution

  • You could use a hash table and then interate over the found fruits and names for returning an array with the values.

    (This answer answers the original question.)

    var data = [{ 'name': 'abby', 'fruit': 'apple' }, { 'name': 'abby', 'fruit': 'apple' }, { 'name': 'abby', 'fruit': 'banana' }, { 'name': 'bobby', 'fruit': 'apple' }, { 'name': 'chris', 'fruit': 'banana' }],
        names = {},
        fruits = {},
        hash = Object.create(null),
        result = [];
    
    data.forEach(function (a) {
        fruits[a.fruit] = true;
        names[a.name] = true;
        hash[a.fruit] = hash[a.fruit] || {};
        hash[a.fruit][a.name] = (hash[a.fruit][a.name] || 0) + 1;
    });
    
    Object.keys(fruits).forEach(function (f, i) {
        Object.keys(names).forEach(function (n, j) {
            result.push([i, j, hash[f][n] || 0]);
        });
    });
    
    console.log(result);

    (This answers the actual question with names and fruits)

    var data = [{ 'name': 'abby', 'fruit': 'apple' }, { 'name': 'abby', 'fruit': 'apple' }, { 'name': 'abby', 'fruit': 'banana' }, { 'name': 'bobby', 'fruit': 'apple' }, { 'name': 'chris', 'fruit': 'banana' }],
        names = {},
        fruits = {},
        hash = Object.create(null),
        result = [];
    
    data.forEach(function (a) {
        fruits[a.fruit] = true;
        names[a.name] = true;
        hash[a.fruit] = hash[a.fruit] || {};
        hash[a.fruit][a.name] = (hash[a.fruit][a.name] || 0) + 1;
    });
    
    Object.keys(fruits).forEach(function (f) {
        Object.keys(names).forEach(function (n) {
            result.push([n, f, hash[f][n] || 0]);
        });
    });
    
    console.log(result);