Професионална програма
Loading...
+ Нов въпрос
SimeonKazandzhiev avatar SimeonKazandzhiev 3 Точки

Plant Discovery от Final Exam

Моля за малко помощ, докарвам логиката но в принтирането се спъвам .

Ако някой има решение на 100/100 моля да сподели .

Ето го и кода ми:

https://pastebin.com/iQqrBpRv

Благодаря предварително

Тагове:
0
Programming Fundamentals
MartinBG avatar MartinBG 3751 Точки

Имаше няколко пропуска по условието, като например да се извежда "error" при невалидна команда, както и да се презаписва rarity, ако растението бъде въведено повече от веднъж в началото.

 

Тази задача би се решила доста по-лесно и прегледно с помощен клас, но ето и оправеното решение с два Map-а :

 

import java.util.*;

public class PlantDiscovery {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        Map<String, Integer> plants = new HashMap<>();
        Map<String, List<Double>> rating = new HashMap<>();

        int n = Integer.parseInt(scanner.nextLine());

        for (int i = 0; i < n; i++) {
            String[] input = scanner.nextLine().split("<->");
            String plant = input[0];
            int rarity = Integer.parseInt(input[1]);
            plants.compute(plant, (k, v) -> rarity);
            rating.putIfAbsent(plant, new ArrayList<>());
        }

        String input;
        while (!"Exhibition".equals(input = scanner.nextLine())) {
            String[] tokens = input.split(": ");
            String command = tokens[0];
            String[] elements = tokens[1].split(" - ");
            String name = elements[0];

            if (!plants.containsKey(name)) {
                System.out.println("error");
                continue;
            }

            switch (command) {
            case "Rate":
                double rate = Double.parseDouble(elements[1]);
                rating.get(name).add(rate);
                break;
            case "Update":
                int rarity = Integer.parseInt(elements[1]);
                plants.compute(name, (k, v) -> rarity);
                break;
            case "Reset":
                rating.get(name).clear();
                break;
            default:
                System.out.println("error");
            }
        }

        System.out.println("Plants for the exhibition:");
        plants.entrySet()
                .stream()
                .sorted(Map.Entry.<String, Integer>comparingByValue()
                        .thenComparingDouble(x -> rating.get(x.getKey()).stream()
                                .mapToDouble(Double::doubleValue)
                                .average().orElse(0.0))
                        .reversed())
                .forEach(e -> System.out.printf("- %s; Rarity: %d; Rating: %.2f%n", e.getKey(), e.getValue(),
                        rating.get(e.getKey()).stream().mapToDouble(Double::doubleValue).average().orElse(0.0)));
    }
}

 

0
SimeonKazandzhiev avatar SimeonKazandzhiev 3 Точки

Благодаря ти много , да знаех че нямах случая за "error", но ме чупеше принтирането и сортирането едновременно на двата мапа,понеже никъде не го бяха показвали и не успях да намеря инфо в интернет.Интересно,досега не бях използвал "compute".Би ли ми обяснил накратко в кои случаи е удобно да се използва.:)

1
MartinBG avatar MartinBG 3751 Точки

@SimeonKazandzhiev

 

Извинявам се за закъснелия отговор.

 

Map#compute(K, BiFunction(K, V)) ни дава възможност едновременно да достъпим и да променим стойността на вече съществуващ ключ. Това е полезно, например, ако искаме да конкатенираме стрингове, както е показано и в документацията:

Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping). For example, to either create or append a String msg to a value mapping:

 
 map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))

 

Друго приложение е, ако искаме да сумираме старата стойност с нова. Например, ако в конкретната задача се искаше при повторно въвеждане на растение новото rarity да се добави към вече съществуващото:

plants.compute(plant, (k, v) -> Objects.requireNonNullElse(v, 0) + rarity);

Забележете, че задължително трябва да се прави проверка за null на старата стойност, преди тя да бъде използвана (ще е null ако растението се въвежда за първи път или ако по някаква причина е имало стойност null). Може да се използва тернарен оператор (примера от официалната документация) или Objects#requireNonNullElse​(T obj, T defaultObj) - и двете правят едно и също в случая.

 

След като изяснихме това, вече сигурно се досещате, че използването на compute в конкретната задача е абсолютно ненужно (и нежелателно) и може да се заменени с Map#put​(K key, V value), което ни дава желаната функционалност, без да събужда въпроси какво прави и защо е използвано (т.е. допринася за четимостта на кода) blush

plants.put(plant, rarity);

 

1
18/11/2020 10:30:02
Georgieva_Nadezhda avatar Georgieva_Nadezhda 28 Точки

Здравей MartinBG,

Можеш ли да напишеш на части разбито по-подробно какво се први в тази част на сортирането без да се ползват готовите методи Map.Entry.<String, Integer>comparingByValue() .thenComparingDouble. Благодаря ти. Разбирам какво е сортирането спрямо уловието, но синтаксиса ми е доста сложен към момента и ако знаеш нещо по-лесно, много ще ми помогнеш :) 

.sorted(Map.Entry.<String, Integer>comparingByValue() .thenComparingDouble(x -> rating.get(x.getKey()).stream() .mapToDouble(Double::doubleValue) .average().orElse(0.0)) .reversed())

1