How to count the number of occurrences of a String in a JSONArray?

3

I'm trying to show the Strings of " specialty " strings that are in my JSON, but when I try to show the count of each "specialty" I can not succeed.

JSON

[
  {
    "id": "20",
    "medico": "ACASIO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "0",
    "receita": "GLUCOBAY 50 MG COM CT BL AL\/AL X 30",
    "horario": "02\/08\/2017",
    "idmedico": "36",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": "REOPRO 2 MG\/ML SOL INJ CT FA VD INC X 5 ML",
    "observacoes": "Cidad\u00e3o com corte profundo no dedo do p\u00e9",
    "tratamento": "HEMOGRAMA",
    "imagem": "logo.png",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "21",
    "medico": "DIEGO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "1",
    "receita": null,
    "horario": "03\/07\/2017",
    "idmedico": "31",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": "",
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "22",
    "medico": "DIEGO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "1",
    "receita": null,
    "horario": "05\/07\/2017",
    "idmedico": "31",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": "ADM. MEDICAMENTO",
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "23",
    "medico": "DIEGO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "1",
    "receita": null,
    "horario": "11\/07\/2017",
    "idmedico": "31",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": "",
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "24",
    "medico": "DIEGO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "1",
    "receita": null,
    "horario": "14\/07\/2017",
    "idmedico": "31",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": "",
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "25",
    "medico": "DIEGO MENDES",
    "paciente": "APARECIDO SOUZA",
    "status": "1",
    "receita": null,
    "horario": "19\/07\/2017",
    "idmedico": "31",
    "idpaciente": "15",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": "",
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  },
  {
    "id": "12",
    "medico": "DIEGO MENDES",
    "paciente": "CARLOS ABREU",
    "status": "0",
    "receita": "GLUCOBAY 50 MG COM CT BL AL\/AL X 30",
    "horario": "24\/07\/2017",
    "idmedico": "31",
    "idpaciente": "12",
    "especialidade": "CLINICO-GERAL",
    "remediosMinistrados": "REOPRO 2 MG\/ML SOL INJ CT FA VD INC X 5 ML",
    "observacoes": "teste",
    "tratamento": "ENDOSCOPIA",
    "imagem": "http:\/\/infasstec.com.br\/desenvolvimento\/android\/hemo.jpg",
    "cidade": "Sumare",
    "unidade": "UPA 24h - Sumare, Casarao",
    "linkReceita": "http:\/\/infasstec.com.br\/desenvolvimento\/android\/receita1.png"
  },
  {
    "id": "14",
    "medico": "DIEGO MENDES",
    "paciente": "ANTONIO DA SILVA",
    "status": "0",
    "receita": "BRONDYNEO 25MG\/5ML XPE INF (VD C\/120ML)",
    "horario": "24\/07\/2017",
    "idmedico": "31",
    "idpaciente": "13",
    "especialidade": "ORTOPEDISTA",
    "remediosMinistrados": "REOPRO 2 MG\/ML SOL INJ CT FA VD INC X 5 ML",
    "observacoes": "Paciente com fortes dores abdominais",
    "tratamento": "ULTRASONOGRAFIA",
    "imagem": "http:\/\/infasstec.com.br\/desenvolvimento\/android\/raio.jpg|http:\/\/infasstec.com.br\/desenvolvimento\/android\/hemo.jpg|http:\/\/infasstec.com.br\/desenvolvimento\/android\/hemo.jpg",
    "cidade": "Campinas",
    "unidade": "UPA - Campinas, Cambui",
    "linkReceita": ""
  },
  {
    "id": "15",
    "medico": "DIEGO MENDES",
    "paciente": "CARLOS ABREU",
    "status": "1",
    "receita": "",
    "horario": "24\/07\/2017",
    "idmedico": "31",
    "idpaciente": "12",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": "",
    "observacoes": "",
    "tratamento": "ULTRASONOGRAFIA",
    "imagem": "",
    "cidade": "Campinas",
    "unidade": "UPA - Campinas",
    "linkReceita": ""
  },
  {
    "id": "16",
    "medico": "RODOLFO PIRES",
    "paciente": "CARLOS ABREU",
    "status": "1",
    "receita": "",
    "horario": "24\/07\/2017",
    "idmedico": "30",
    "idpaciente": "12",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": "",
    "observacoes": "",
    "tratamento": "ENDOSCOPIA",
    "imagem": "",
    "cidade": "Sumare",
    "unidade": "UPA 24h - Sumare, Casarao",
    "linkReceita": ""
  },
  {
    "id": "18",
    "medico": "DIEGO MENDES",
    "paciente": "CARLOS ABREU",
    "status": "1",
    "receita": null,
    "horario": "24\/07\/2017",
    "idmedico": "31",
    "idpaciente": "12",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": null,
    "imagem": "",
    "cidade": "Sumare",
    "unidade": "UPA 24h - Sumare, Casarao",
    "linkReceita": ""
  },
  {
    "id": "13",
    "medico": "DIEGO MENDES",
    "paciente": "ANTONIO DA SILVA",
    "status": "1",
    "receita": null,
    "horario": "25\/07\/2017",
    "idmedico": "31",
    "idpaciente": "13",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": null,
    "imagem": "",
    "cidade": "Sumare",
    "unidade": "UPA 24h - Sumare, Casarao",
    "linkReceita": ""
  },
  {
    "id": "19",
    "medico": "DIEGO MENDES",
    "paciente": "TENORIO FIGUEIREDO",
    "status": "1",
    "receita": null,
    "horario": "28\/07\/2017",
    "idmedico": "31",
    "idpaciente": "14",
    "especialidade": "CIRURGIAO",
    "remediosMinistrados": null,
    "observacoes": null,
    "tratamento": null,
    "imagem": "",
    "cidade": "",
    "unidade": "",
    "linkReceita": ""
  }
] 

In this JSON I just want to get the count of each "specialty"

MainActivity.java

array = new JSONArray(s);
int i = 0;
List < Consulta > consultas = new ArrayList<> ();
String dados = "";
while (i < array.length()) {
    JSONObject obj = array.getJSONObject(i);

    int id = obj.getInt("id");
    String paciente = obj.getString("paciente");
    int status = obj.getInt("status");
    String rece = obj.getString("receita");
    String horario = obj.getString("horario");
    idmedico = obj.getString("idmedico");
    idpaciente = obj.getString("idpaciente");
    String remedios = obj.getString("remediosMinistrados");
    String observacoes = obj.getString("observacoes");
    String tratamento = obj.getString("tratamento");
    String imagem = obj.getString("imagem");
    String linkreceita = obj.getString("linkReceita");
    String espec = obj.getString("especialidade");
    String medico = obj.getString("medico");

    Map <String, Integer> contagemPorEspecialidade = new HashMap<>();

    for (int k = 0; k < array.length(); k++) {
        JSONObject key = array.getJSONObject(k);

        if (contagemPorEspecialidade.containsKey(espec)) {
            Integer count = contagemPorEspecialidade.get(espec);
            contagemPorEspecialidade.put(espec, count + 1);
        } else {
            contagemPorEspecialidade.put(espec, 1);
        }

    }
    for (Map.Entry<String, Integer> val: contagemPorEspecialidade.entrySet()) {
        Toast.makeText(activity, val.getKey() + " occurs " + val.getValue() + " time(s)", Toast.LENGTH_SHORT).show();
    }
}

In this last Toast I only get the name of the specialty 13 times, no matter if the specialty appeared 1 or 2 times it is always showing 13, am I doing the wrong logic? Or did I just make mistakes?

    
asked by anonymous 11.09.2017 / 19:11

2 answers

5

Your logic is not at all wrong, the problem is that you are putting in the loop of repetition. So every time you search for a new item in JSON, your specialty array is zeroed. To solve this, you will have to create a ArrayList to store the specialties and a HashMap to count before while . See:

ArrayList<String> listEspecialidades = new ArrayList<>();
HashMap<String, Integer> contagemPorEspecialidade = new HashMap<>();
while (i < array.length()) {
  // aqui resgate do conteúdo do array
}

Soon after, within while you store in your listEspecialidades array which is in specialty using the add() method. See:

while (i < array.length()) {

  String espec = obj.getString("especialidade");
  // adição da especialidade no array
  listEspecialidades.add(espec);

  // aqui resgate do restante do conteúdo do array
}

Once this is done, after finishing the loop, you create the condition to check the repeated ones. See:

for (int i = 0; i < listEspecialidades.size(); ++i) {
    String item = listEspecialidades.get(i);
    // comparação se já existe uma especialidade no array
    if (contagemPorEspecialidade.containsKey(item))
        contagemPorEspecialidade.put(item, contagemPorEspecialidade.get(item) + 1);
    else
        contagemPorEspecialidade.put(item, 1);
}

StringBuilder sb = new StringBuilder();

// laço para concatenar os valores em um StringBulder  
for (Map.Entry < String, Integer > e: contagemPorEspecialidade.entrySet()) {
    // concatena as especialidade com a quantidade de repetições
    sb.append("\n").append(e.getKey()).append(" : ").append(e.getValue());
}
// imprime o conteúdo do StringBuilder
System.out.print(sb.toString());

This would be the result:

ORTOPEDISTA: 1 
CIRURGIAO: 11 
CLINICO-GERAL: 1 

See working on ideone .

    
12.09.2017 / 14:11
3

You're doing a lot of unnecessary operations on your code. I rewrote the method for counting as follows:

private static Map<String, Integer> contar(JSONArray array) {
  List<String> ocorrencias = new ArrayList<>();
  Set<String> especialidades = new TreeSet<>();
  Map<String, Integer> resultado = new TreeMap<>(); // TreeMap para manter o Map ordenado pelas chaves

  // Percorre o array guardando as especialidades nas coleções com duplicidades e sem
  array.forEach((Object item) -> {
    JSONObject objeto = (JSONObject) item;
    String especialidade = objeto.getString("especialidade");

    ocorrencias.add(especialidade);
    especialidades.add(especialidade);
  });

  // Percorre a coleção sem duplicidades
  especialidades.forEach((String especialidade) -> {
    Integer quantidade;

    // Verifica a frequência que aquela especialidade aparece em duplicadade
    quantidade = Collections.frequency(ocorrencias, especialidade);
    resultado.put(especialidade, quantidade);
  });

  return resultado;
}

In this method we store two collections of specialties, one without repeating and one with all repetitions, and set a Map to the count of repeats. To test the method you can do as follows:

JSONArray array = new JSONArray(/* Aqui vai o seu JSON */);
Map<String, Integer> especialidades;

especialidades = contar(array);
especialidades.forEach((chave, valor) -> System.out.println(chave + " occurs " + valor + " time(s)"));
CIRURGIAO occurs 11 time(s)
CLINICO-GERAL occurs 1 time(s)
ORTOPEDISTA occurs 1 time(s)
    
12.09.2017 / 14:06