1

I'm trying to solve This problem in BeeCrowd without using a ton of if/elses.

BeeCrowd problem

It consists of reading 3 inputs from use, ex:

vertebrado
ave
carnivoro

and outputting the correspondent word of those inputs.

aguia

I know more python than java, this would be my solution in python (which works):

dict = {
  "vertebrado": {
    "ave": {
      "carnivoro": "aguia",
      "onivoro": "pomba"
    },
    "mamifero": {
      "onivoro": "homem",
      "herbivoro": "vaca"
    }
  },
  "invertebrado": {
    "inseto": {
      "hematofago": "pulga",
      "herbivoro": "lagarta"
    },
    "anelideo": {
      "hematofago": "sanguessuga",
      "onivoro": "minhoca"
    }
  }
}

word1 = input()
word2 = input()
word3 = input()

word = dict[word1][word2][word3]

print(word)

However I'm struggling to code a good solution in Java. This is my current Java solution (which also works):

import java.util.Scanner;
import java.util.HashMap;

public class Main {
    public static void main (String[]args) {
        Scanner scanner = new Scanner(System.in);
        String word1 = new String(scanner.nextLine());
        String word2 = new String(scanner.nextLine());
        String word3 = new String(scanner.nextLine());
        
        HashMap<String, HashMap<String, HashMap<String, String>>> dict = new HashMap();
        dict.put("vertebrado",  new HashMap<String, HashMap<String, String>>());
        dict.put("invertebrado", new HashMap<String, HashMap<String, String>>());
        
        dict.get("vertebrado").put("ave", new HashMap<String, String>());
        dict.get("vertebrado").put("mamifero", new HashMap<String, String>());
        
        dict.get("invertebrado").put("inseto", new HashMap<String, String>());
        dict.get("invertebrado").put("anelideo", new HashMap<String, String>());
        
        dict.get("vertebrado").get("ave").put("carnivoro", "aguia");
        dict.get("vertebrado").get("ave").put("onivoro", "pomba");
        dict.get("vertebrado").get("mamifero").put("onivoro", "homem");
        dict.get("vertebrado").get("mamifero").put("herbivoro", "vaca");
        
        dict.get("invertebrado").get("inseto").put("hematofago", "pulga");
        dict.get("invertebrado").get("inseto").put("herbivoro", "lagarta");
        dict.get("invertebrado").get("anelideo").put("hematofago", "sanguessuga");
        dict.get("invertebrado").get("anelideo").put("onivoro", "minhoca");
        
        
        String word = dict.get(word1).get(word2).get(word3);
        
        System.out.println(word);
    }
}

The obvious issue with that solution is that it's unpractical to populate the dict that way. The code is already big. If dict had a lot values, with a lot of "depth", it will become a hell to maintain.

Is there a way to reduce it? IE, declaring and initializing dict in a couple of lines?

Sunderam Dubey
  • 1
  • 11
  • 20
  • 40
nluizsoliveira
  • 355
  • 1
  • 9
  • 1
    depends on how you store the data that should be contained in `dict`. Looking at you python example, you pretty much have a JSON which you use as input. You can do the same in java. Provide a JSON file with the desired data and depth and read it in java. [How to read JSON?](https://stackoverflow.com/a/31743324/7109162) – XtremeBaumer May 30 '22 at 07:26
  • That would be perfect for this example @XtremeBaumer! I'll search about transforming a JSON into a dict, thanks! If it happens that the final key were Java variables/functions, would that work too? – nluizsoliveira May 30 '22 at 07:27
  • 1
    Well, since Java 9, there is the `Map::of` method, which allows to trim down your code a little. – MC Emperor May 30 '22 at 07:27
  • Searching about `Map::of` , thanks @MCEmperor! – nluizsoliveira May 30 '22 at 07:28

1 Answers1

5

Use Map.of() as MC Emperor suggested:

Map<String, Map<String, Map<String, String>>> dict = Map.of(
    "vertebrado",
        Map.of(
            "ave",
                Map.of(
                    "carnivoro", "aguia",
                    "onivoro", "pomba"
                ),
            "mamifero",
                Map.of("onivoro","homem",
                        "herbivoro","vaca"
                )
        ),
    "invertebrado",
        Map.of(
            "inseto",
                Map.of(
                    "hematofago", "pulga",
                    "herbivoro", "lagarta"
                ),
            "anelideo",
                Map.of(
                    "hematofago","sanguessuga",
                    "onivoro","minhoca"
                )
        )
);

Compared to using a json file this also gives you type checking as you go, although to be really type safe you would want to introduce classes named Phylum, Class and Order to wrap your Strings, instead of leaving values "Stringly typed".

nluizsoliveira
  • 355
  • 1
  • 9
tgdavies
  • 10,307
  • 4
  • 35
  • 40
  • This will only work till 3rd level of parent right ? – Sayan Bhattacharya May 30 '22 at 07:32
  • 1
    Yes, which is correct for the domain as modelled -- if you try to access data which isn't there you will get a compile time error, likewise you can't fail to completely construct the tree without typing a `null`. – tgdavies May 30 '22 at 07:36
  • 1
    If you were modelling down to Family level you'd declare your `Map` with an extra level. – tgdavies May 30 '22 at 07:37
  • I discovered Map.of() has a limitation of 10 entries, you need to use Map.ofEntries to use unlimited entries which is more verbose :c – nluizsoliveira May 31 '22 at 04:47