Dynamic grouping of JSON data

Asked

Viewed 713 times

8

I have been trying for a few days to perform JSON data grouping dynamically, but without success, it is a matter of logic rather than programming itself.

Given an array of objects(Users), group them according to their attributes(name, age, etc).

The grouping must be dynamic and the result will be displayed according to the chosen attributes.

JSON:

var lUsuarios = [{
    "NOME":"ANTONIO CARLOS CURY",
    "IDADE": 28,
    "SEXO": "MASCULINO",
    "ADMINISTRADOR": true
},{
    "NOME":"CESAR SIQUEIRA JUNIOR",
    "IDADE": 23,
    "SEXO": "MASCULINO",
    "ADMINISTRADOR": false
},{
    "NOME":"ANDREI SALVADOR",
    "IDADE": 18,
    "SEXO": "MASCULINO",
    "ADMINISTRADOR": true
},{
    "NOME":"SERGIO MORO",
    "IDADE": 35,
    "SEXO": "MASCULINO",
    "ADMINISTRADOR": false
},{
    "NOME":"MARIA DA SILVA",
    "IDADE": 17,
    "SEXO": "FEMININO",
    "ADMINISTRADOR": true,
},{
    "NOME":"JOANA FINA",
    "IDADE": 19,
    "SEXO": "FEMININO",
    "ADMINISTRADOR": false
},{
    "NOME":"ELIANE DA SILVA",
    "IDADE": 21,
    "SEXO": "FEMININO",
    "ADMINISTRADOR": true,
},{
    "NOME":"MARIA BONITA",
    "IDADE": 47,
    "SEXO": "FEMININO",
    "ADMINISTRADOR": false
}]</code>

Function group:

function AgruparJSON(colunas){
    //Throw new Exception("Não sei o que vai aqui");
}

Method call:

The great difficulty is in the compound groupings, where they will be grouped by two or more attributes of the user list (JSON).

$(function(){

    //JSON de dados dos usuários
    var lUsuarios = JSON.parse('[{...}]');

    var lUsuariosSexoAdministrador = lUsuarios.AgruparJSON("SEXO", "ADMINISTRADOR");    
    console.log(lUsuariosSexoAdministrador);

    //Resultado esperado para console.log(lUsuariosSexoAdministrador);
    [{"MASCULINO":
        [{ "true" : [{
                        "NOME":"ANTONIO CARLOS CURY",
                        "IDADE": 28,
                        "SEXO": "MASCULINO",
                        "ADMINISTRADOR": true
                    },{
                        "NOME":"ANDREI SALVADOR",
                        "IDADE": 18,
                        "SEXO": "MASCULINO",
                        "ADMINISTRADOR": true}]
        },{ "false": [{
                        "NOME":"CESAR SIQUEIRA JUNIOR",
                        "IDADE": 23,
                        "SEXO": "MASCULINO",
                        "ADMINISTRADOR": false
                    },{
                        "NOME":"SERGIO MORO",
                        "IDADE": 35,
                        "SEXO": "MASCULINO",
                        "ADMINISTRADOR": false
                    }]
        }]
    },{"FEMININO":
        [{ "true" : [{
                        "NOME":"MARIA DA SILVA",
                        "IDADE": 17,
                        "SEXO": "FEMININO",
                        "ADMINISTRADOR": true
                    },{
                        "NOME":"ELIANE DA SILVA",
                        "IDADE": 21,
                        "SEXO": "FEMININO",
                        "ADMINISTRADOR": true
                    }]
        },{ "false": [{
                        "NOME":"MARIA BONITA",
                        "IDADE": 47,
                        "SEXO": "FEMININO",
                        "ADMINISTRADOR": false
                    },{
                        "NOME":"JOANA FINA",
                        "IDADE": 19,
                        "SEXO": "FEMININO",
                        "ADMINISTRADOR": false
                    }]
        }]
    }]; 
});
  • Hello @Guilhermecostamilam ! Thanks for the answer, I had already read this question that recommended me, the problem are the groupings "children", for when there is more than one grouping, they do not respect the groupings "parents", I need to generate the groupings "children" respecting the grouping "Father", as I tried to show in the Satida of the method: Agruparjson("SEX", "ADMINISTRATOR")

2 answers

2


Here is a simple algorithm that groups your data based on an arbitrary amount of attributes:

var lUsuarios=[{"NOME":"ANTONIO CARLOS CURY","IDADE":28,"SEXO":"MASCULINO","ADMINISTRADOR":true},{"NOME":"CESAR SIQUEIRA JUNIOR","IDADE":23,"SEXO":"MASCULINO","ADMINISTRADOR":false},{"NOME":"ANDREI SALVADOR","IDADE":18,"SEXO":"MASCULINO","ADMINISTRADOR":true},{"NOME":"SERGIO MORO","IDADE":35,"SEXO":"MASCULINO","ADMINISTRADOR":false},{"NOME":"MARIA DA SILVA","IDADE":17,"SEXO":"FEMININO","ADMINISTRADOR":true},{"NOME":"JOANA FINA","IDADE":19,"SEXO":"FEMININO","ADMINISTRADOR":false},{"NOME":"ELIANE DA SILVA","IDADE":21,"SEXO":"FEMININO","ADMINISTRADOR":true},{"NOME":"MARIA BONITA","IDADE":47,"SEXO":"FEMININO","ADMINISTRADOR":false}];

// complexidade aproximada de O(2N * C), onde:
// N = length de "lUsuarios"
// C = length de "colunas"
function AgruparJSON(colunas){
	var colsObjData = {};

	// 1. agrupamos por categorias em chaves que são a concatenação dos valores
	// das colunas desejas, something like "MASCULINO;true" ou "FEMININO;false"
	lUsuarios.forEach(function(userObj) {
		var key = colunas.reduce(function(a, b) {
			return (a ? a + ';' : a) + userObj[b];
		}, '');
		if (!(key in colsObjData)) {
			colsObjData[key] = [];
		}
		colsObjData[key].push(userObj);
	});

	// 2. já possuimos os agrupamentos, agora é apenas uma questão de transformar eles 
	// na estrutura desejada
	var finalData = {};
	for (var key in colsObjData) {
		var data = finalData;
		var splited = key.split(';');
		splited.forEach(function(col, index) {
			if (!(col in data)) {
				data[col] = {}
			}
			if (index === splited.length - 1) {
				data[col] = colsObjData[key];
			}
			else {
				data = data[col];
			}
		});
	}
	return finalData;
}

var result = AgruparJSON(["SEXO", "ADMINISTRADOR"]);
document.writeln(JSON.stringify(result));

Obs:

  • The return of AgruparJSON It is not exactly in the format you want, I used a simpler and compact model, but it still preserves the grouping properties. If you really need it to be in the format you posted in the question is simple to convert.
  • The algorithm assumes that all data values in JSON are of types primitive. It would be possible to extend to work with other types, but then it would depend on what exactly they are.

Pretty print of the result:

{
  "MASCULINO": {
    "true": [
        {
            "NOME": "ANTONIO CARLOS CURY",
            "IDADE": 28,
            "SEXO": "MASCULINO",
            "ADMINISTRADOR": true
        },
        {
            "NOME": "ANDREI SALVADOR",
            "IDADE": 18,
            "SEXO": "MASCULINO",
            "ADMINISTRADOR": true
        }
    ],
    "false": [
        {
            "NOME": "CESAR SIQUEIRA JUNIOR",
            "IDADE": 23,
            "SEXO": "MASCULINO",
            "ADMINISTRADOR": false
        },
        {
            "NOME": "SERGIO MORO",
            "IDADE": 35,
            "SEXO": "MASCULINO",
            "ADMINISTRADOR": false
        }
    ]
  },
  "FEMININO": {
    "true": [
        {
            "NOME": "MARIA DA SILVA",
            "IDADE": 17,
            "SEXO": "FEMININO",
            "ADMINISTRADOR": true
        },
        {
            "NOME": "ELIANE DA SILVA",
            "IDADE": 21,
            "SEXO": "FEMININO",
            "ADMINISTRADOR": true
        }
    ],
    "false": [
        {
            "NOME": "JOANA FINA",
            "IDADE": 19,
            "SEXO": "FEMININO",
            "ADMINISTRADOR": false
        },
        {
            "NOME": "MARIA BONITA",
            "IDADE": 47,
            "SEXO": "FEMININO",
            "ADMINISTRADOR": false
        }
    ]
  }
}

-1

I know it’s been a while since I responded but I found a way to do what I wanted, just to update here

function agruparJSON(coluna, valor) {
    var array = []
    for(i=0;i<lUsuarios.length;i++) {
        if (lUsuarios[i][coluna] == valor) {
            array.push(lUsuarios[i])
        }
    }
    return array
}

agruparJSON('SEXO', 'MASCULINO')
  • Thanks for the help! Unfortunately your solution does not solve my problem, because the groupers should be dynamic. In your solution I would have to create a filter for each possible grouper.

  • I edited it and it got a little better, but it’s not exactly what you want

  • I found a way to do it, but it’s limited to one filter at a time

Browser other questions tagged

You are not signed in. Login or sign up in order to post.