1

I am trying to convert a loop that I have made into Java streams, though the code uses iterators and I am finding it hard to convert it into readable code.

private void printKeys() throws IOException {
    ClassLoader classLoader = getClass().getClassLoader();

    // read a json file
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode root = objectMapper.readTree(classLoader.getResource("AllSets.json"));
    Set<String> names = new HashSet<>();

    // loop through each sub node and store the keys
    for (JsonNode node : root) {
        for (JsonNode cards : node.get("cards")) {
            Iterator<String> i = cards.fieldNames();
            while(i.hasNext()){
                String name = i.next();
                names.add(name);
            }
        }
    }

    // print each value
    for (String name : names) {
        System.out.println(name);
    }

   }

I have tried the following though I feel like its not going the right way.

List<JsonNode> nodes = new ArrayList<>();
root.iterator().forEachRemaining(nodes::add);

Set<JsonNode> cards = new HashSet<>();
nodes.stream().map(node -> node.get("cards")).forEach(cards::add);

Stream s = StreamSupport.stream(cards.spliterator(), false);
//.. unfinished and unhappy

You can find the Json file I used here: https://mtgjson.com/json/AllSets.json.zip Be warned its quite large.

2
  • Could you attach AllSets.json to test code, please? Commented Dec 23, 2016 at 14:37
  • @AndriiAbramov I added a link to the file in the question. Commented Dec 23, 2016 at 16:14

3 Answers 3

3

You can do most of the things in one swoop, but it's a shame this json api does not support streams better.

List<JsonNode> nodes = new ArrayList<>();
root.iterator().forEachRemaining(nodes::add);

Set<String> names = nodes.stream()
    .flatMap(node -> StreamSupport.stream(
        node.get("cards").spliterator(), false))
    .flatMap(node -> StreamSupport.stream(
        ((Iterable<String>) () -> node.fieldNames()).spliterator(), false))
    .collect(Collectors.toSet());

Or with Patrick's helper method (from the comments):

Set<String> names = stream(root)
    .flatMap(node -> stream(node.get("cards")))
    .flatMap(node -> stream(() -> node.fieldNames()))
    .collect(Collectors.toSet());

...

public static <T> Stream<T> stream(Iterable<T> itor) {
    return StreamSupport.stream(itor.spliterator(), false);
}

And printing:

names.stream().forEach(System.out::println);
Sign up to request clarification or add additional context in comments.

1 Comment

This could look a lot better with a helper method public static <T> Stream<T> stream(Iterable<T> itor) { return StreamSupport.stream(itor.spliterator(), false); }
0

If you provide 'json' file to us, it will be very useful.

At least now, I can make some suggestions to you:

Set<JsonNode> cards = new HashSet<>();
nodes.stream().map(node -> node.get("cards")).forEach(cards::add);

Replace with:

Set<JsonNode> cards = nodes.stream().map(node -> node.get("cards")).collect(Collectors.toSet());

for (String name : names) {
    System.out.println(name);
}

Replace with:

names.forEach(System.out::println);

1 Comment

Added a link to the json file in the original question
0

Replace

Set<JsonNode> cards = new HashSet<>();

with

List<JsonNode> cards = new ArrayList<>();

Remove

Stream s = StreamSupport.stream(cards.spliterator(), false);

Then add below lines

cards.stream().forEach( card -> {
    Iterable<String> iterable = () -> card.fieldNames();
    Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
    targetStream.forEach(names::add);
});
names.forEach(System.out::println);

Comments

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.