Metoda zwracająca inicjały

0

Cześć. Pisałem dzisiaj takie zadanko na kartce. Napisz metodę która zwraca inicjały - public static String demoInitials (String fullname). Metoda ma zwracać uwagę na wszelkie błędy typu pusty String, czy np napisanie samego imienia.
Teraz przysiadłem do komputera i nawet na komputerze ciężko jest mi wymyśleć rozwiązanie.
Napisałem coś takiego(co jest mocno niepoprawne....) co tylko działa oczywiście w przypadku poprawnego napisania imienia i nazwiska z dużej litery. Ale nie wiem co zrobić żeby to działało tak, że bierze pierwszy znak za spacją jako inicjał nazwiska.

 public static String demoInitials(String fullName) {
        String firstInitial = fullName.substring(0, 1);
        String secondInitial = null;

     for (int i = 1; i < fullName.length(); i++) {
         if (Character.isUpperCase(fullName.charAt(i))) {
             secondInitial = String.valueOf(fullName.charAt(i));

         }

     }



        return firstInitial + " " + secondInitial;

    }
}
1

Najłatwiej to zrobić strumieniami i metodą .split() po prostu;

        List<Character> initials = Stream.of(x.trim().split(" "))
            .filter(s -> !s.isEmpty())
            .map(s -> s.charAt(0))
            .collect(Collectors.toList());
0
  1. Przed wyciągnięciem firstInitial sprawdź, czy fullName jest pusty - jak jest to rzuć błędem
  2. Jak pobierzesz firstInitial sprawdź czy jest uppercasem - jeśli nie, to rzuć błędem
  3. Po zakończonej pętli sprawdź, czy secondInitial jest nullem - jeśli jest, to znaczy, że jest samo imie i rzuć błędem
  4. Potem sprawdź, czy secondInitial jest uppercasem - jeśli nie, to rzuć błędem

Poza tym, możesz użyć metody split i jako delimiter użyć spacji. Wtedy ci podzieli stringa. Powinieneś dostać dwa stringi, z czego każdy powinien się zaczynac od duzej litery. W przeciwnym wypadku: rzuć błąd

0

Mam tylko imię i nazwisko, wiec słabo się orientuję w inicjalach takich osób jak sędzia Anna Maria Wesołowska lub Jan Maria Rokita. Ale zwróciłbym uwagę na takie przypadki

3

Podejście "na taśmę klejącą" jest niezbyt profesjonalne i sugeruje niewłaściwe rozumienie zadania. Prawidłową odpowiedzią jest implementacja algorytmu w formie maszyny stanów. Oprócz użycia właściwego wzorca należy zadbać o prawidłowy rozdział odpowiedzialności, przejrzystość referencyjną i oddzielenie efektów ubocznych, jak wreszcie ogólną czytelność kodu.

Ja bym to na szybko opracował tak:

public class DemoInitialStateMachine {
    enum State {
        SCANNING_FOR_NAME_INITIAL,
        SCANNING_FOR_SPACE,
        SCANNING_FOR_LAST_NAME_INITIAL,
        SCAN_COMPLETED
    }

    interface CharPredicate {
        boolean matches(Character character);
    }

    interface SideEffectExecutor<T> {
        void executeSideEffect(Character input, T receiver);
    }

    private static final Map<State, CharPredicate> predicates = new HashMap<State, CharPredicate>() {
        {
            put(State.SCANNING_FOR_NAME_INITIAL, new CharPredicate() {
                @Override
                public boolean matches(Character character) {
                    return Character.isUpperCase(character);
                }
            });
            put(State.SCANNING_FOR_SPACE, new CharPredicate() {
                @Override
                public boolean matches(Character character) {
                    return character == ' ';
                }
            });
            put(State.SCANNING_FOR_LAST_NAME_INITIAL, new CharPredicate() {
                @Override
                public boolean matches(Character character) {
                    return Character.isUpperCase(character);
                }
            });
        }
    };

    private static final Map<State, SideEffectExecutor<StringBuilder>> sideEffectExecutors = new HashMap<State, SideEffectExecutor<StringBuilder>>() {
        {
            put(State.SCANNING_FOR_NAME_INITIAL, new SideEffectExecutor<StringBuilder>() {
                @Override
                public void executeSideEffect(Character input, StringBuilder receiver) {
                    receiver.append(input);
                }
            });
            put(State.SCANNING_FOR_LAST_NAME_INITIAL, new SideEffectExecutor<StringBuilder>() {
                @Override
                public void executeSideEffect(Character input, StringBuilder receiver) {
                    receiver
                            .append(" ")
                            .append(input);
                }
            });
        }
    };

    private static final Map<State, State> transitions = new HashMap<State, State>() {
        {
            put(State.SCANNING_FOR_NAME_INITIAL, State.SCANNING_FOR_SPACE);
            put(State.SCANNING_FOR_SPACE, State.SCANNING_FOR_LAST_NAME_INITIAL);
            put(State.SCANNING_FOR_LAST_NAME_INITIAL, State.SCAN_COMPLETED);
        }
    };

    private static final State INITIAL_STATE = State.SCANNING_FOR_NAME_INITIAL;
    private static State currentState = INITIAL_STATE;

    public static String demoInitials(String fullName) {
        int counter = 0;
        StringBuilder initials = new StringBuilder();
        while (currentState != State.SCAN_COMPLETED) {
            if (counter == fullName.length()) {
                currentState = State.SCAN_COMPLETED;
            } else {
                char character = fullName.charAt(counter++);
                if (predicates.containsKey(currentState)) {
                    if (predicates.get(currentState).matches(character)) {
                        if (sideEffectExecutors.containsKey(currentState)) {
                            sideEffectExecutors.get(currentState).executeSideEffect(character, initials);
                        }
                        currentState = transitions.get(currentState);
                    }
                }
            }
        }
        resetState();
        return initials.toString();
    }

    private static void resetState() {
        currentState = INITIAL_STATE;
    }
}
2

Okej ale to było zadanie na kartkę na 10min. Doświadczonym osobom pewnie to nie robi dużej różnicy czy pisze się na kartce czy na komputerze jednak dla mnie to jest spore utrudnienie

1

Ja to właśnie napisałem sobie na kartce i od razu przepisałem na forum. Nie otwierałem nawet IDE. To tylko kwestia treningu.

0

Ale że co?! Mam nadzieję, że twój post, to nieudany żart. Abstrahując, że to strzelanie z armaty do muchy, to najbardziej komiczna jest deklaracja "czystego kodu" =D

@Paweł123
Nie bierz z tego przykładu

1

Nie twierdzę przecież, że ten kod jest doskonały. (Coś takiego jak perfekcyjny kod moim zdaniem wprost nie istnieje). Masz rację, że przydałyby się komentarze, czy np. logowanie.. Podałem rozwiązanie w wersji uproszczonej dla celów poglądowych.

0
V-2 napisał(a):

Podałem rozwiązanie w wersji uproszczonej dla celów poglądowych.

Niestety musisz posłuchać @Tyvrel - taki over-engineering to strzelanie wręcz z czołgu do muchy. Niby enumy, polimorfizm, interfejsy, a potem oczywiście if'ologia w demoInitials(). Nie mówiąc o tym że zamiast CharPredicate mogłeś użyć javowego Predicate<Character>. Poza tym - jakie komentarze i logowanie w takiej odseparowanej części aplikacji jak ta? ;o

@Paweł123 Twoje rozwiązanie jest proste - jest ok, nie polegaj na rozwiązaniu od @V-2

0
TomRiddle napisał(a):
V-2 napisał(a):

Podałem rozwiązanie w wersji uproszczonej dla celów poglądowych.

Niestety musisz posłuchać @Tyvrel - taki over-engineering to strzelanie wręcz z czołgu do muchy. Niby enumy, polimorfizm, interfejsy, a potem oczywiście if'ologia w demoInitials().

Właśnie to mi się trochę nie podobało. Co byś radził? Wydaje mi się, że można by tego uniknąć, gdyby scalić CharPredicate, SideEffectExecutor i "namiar" na następny stan w jakąś jedną, nadrzędną klasę. Wtedy można by usunąć ten niezbyt elegancki kod warunkowy z wnętrza pętli.

Nie mówiąc o tym że zamiast CharPredicate mogłeś użyć javowego Predicate<Character>.

Masz rację, nie pomyślałem o tym. Właśnie dlatego podkreślałem, że nie twierdzę, że kod jest perfekcyjny. Nie wydaje mi się jednak, żeby było fair dyskwalifikowanie całej propozycji na podstawie jednego potknięcia.

Ten kod można by bardzo uprościć, gdyby wolno było używać Kotlina. Wtedy najlepsze byłoby rozwiązanie bardziej funkcyjne.

fun demoInitials(fullName: String) = listOf<(Char) -> Boolean>(
        Character::isUpperCase,
        { it == ' ' },
        Character::isUpperCase)
            .fold("" to fullName) {
                (initials, remainingString), predicate ->
                    remainingString
                            .dropWhile {
                                predicate(it).not()
                            }
                            .let {
                                it.firstOrNull()?.toString().orEmpty() to it.drop(1)
                            }
                            .let { (captured, remaining) ->
                                (initials + captured) to remaining
                            }
            }
            .first
            .trim()

Teraz nie ma już enumów, o wiele mniej LOC i trudno oskarżać o przeinżynierowanie. Niestety jako androidowiec nie wiem, jak napisać to w tych nowych Javach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1