Mam kod, który ma sekwencję if
s, która działa, ale po prostu niechlujny. Zasadniczo chcę wybrać największą z trzech liczb całkowitych i ustawić flagę statusu, aby powiedzieć, która została wybrana. Mój obecny kod wygląda następująco:
a = countAs();
b = countBs();
c = countCs();
if (a > b && a > c)
status = MOSTLY_A;
else if (b > a && b > c)
status = MOSTLY_B;
else if (c > a && c > b)
status = MOSTLY_C;
else
status = DONT_KNOW;
Ten wzór występuje kilka razy, a przy długich nazwach zmiennych trudno jest wizualnie potwierdzić, że każda z nich if
jest poprawna. Wydaje mi się, że może być lepszy i jaśniejszy sposób na zrobienie tego; czy ktoś może coś zasugerować?
Istnieje kilka potencjalnych duplikatów, ale nie do końca odpowiadają temu pytaniu.
W sugerowanym duplikacie: Podejścia do sprawdzania wielu warunków? wszystkie sugerowane rozwiązania wydają się równie nieporadne jak oryginalny kod, więc nie zapewniają lepszego rozwiązania.
I ten post Eleganckie sposoby radzenia sobie, jeśli (jeśli inaczej) dotyczą tylko poziomów zagnieżdżenia i asymetrii, co nie jest tutaj problemem.
źródło
Odpowiedzi:
Rozłóż logikę na czynniki, wróć wcześniej
Jak sugerowano w komentarzach, wystarczy po prostu zawinąć logikę w funkcję i wyjść wcześniej z
return
's', aby znacznie uprościć sprawę . Można również rozłożyć na czynniki trochę funkcjonalność, delegując testy do innej funkcji. Bardziej konkretnie:To jest krótsze niż moja poprzednia próba:
Powyższe jest nieco bardziej szczegółowe, ale jest łatwe do odczytania IMHO i nie oblicza porównań wiele razy.
Potwierdzenie wizualne
W swojej odpowiedzi mówisz:
... również w swoim pytaniu mówisz:
Mogę nie rozumieć, co próbujesz osiągnąć: czy chcesz skopiować i wkleić wzór wszędzie tam, gdzie go potrzebujesz? Z funkcji takich jak ten powyżej, przechwytywanie wzorca raz i sprawdzić raz na zawsze, że wszystkie porównania użyć
a
,b
ac
w razie potrzeby. Następnie nie musisz się już martwić, kiedy wywołujesz tę funkcję. Oczywiście, może w praktyce twój problem jest nieco bardziej złożony niż opisany przez Ciebie: jeśli tak, proszę dodaj szczegóły, jeśli to możliwe.źródło
MOSTLY_A
lubMOSTLY_C
w przypadkua == c
aa > b
. Zostało to naprawione. Dzięki.TL: DR; Twój kod jest już poprawny i „czysty”.
Widzę wielu ludzi wahających się wokół odpowiedzi, ale wszyscy tęsknią za lasem przez drzewa. Zróbmy pełną informatykę i analizę matematyczną, aby całkowicie zrozumieć to pytanie.
Po pierwsze, zauważamy, że mamy 3 zmienne, każda z 3 stanami: <, = lub>. Całkowita liczba permutacji wynosi 3 ^ 3 = 27 stanów, do których przypisam unikalny numer, oznaczony P #, dla każdego stanu. Ten numer P # to system liczb czynnikowych .
Zliczając wszystkie permutacje, które mamy:
Po kontroli stwierdzamy, że mamy:
Napiszmy program (patrz przypis), aby wyliczyć wszystkie te permutacje wartościami A, B i C. Sortowanie stabilne według P #:
Jeśli zastanawiasz się, skąd wiedziałem, które stany P # są niemożliwe, teraz już wiesz. :-)
Minimalna liczba porównań w celu ustalenia kolejności wynosi:
Log2 (27) = Log (27) / Log (2) = ~ 4,75 = 5 porównań
tzn. rdzeń rdzeniowy dał prawidłową 5 minimalną liczbę porównań. Sformatowałbym jego kod jako:
W przypadku Twojego problemu nie zależy nam na testowaniu równości, więc możemy pominąć 2 testy.
Nie ma znaczenia, jak czysty / zły jest kod, jeśli otrzyma złą odpowiedź, więc jest to dobry znak, że poprawnie załatwiasz wszystkie sprawy!
Następnie, jeśli chodzi o prostotę, ludzie próbują „poprawić” odpowiedź, w której ich zdaniem poprawa oznacza „optymalizację” liczby porównań, ale nie jest to dokładnie to, o co prosisz. Zdezorientowałeś wszystkich, gdy zapytałeś „Czuję, że może być lepszy”, ale nie zdefiniowałeś, co oznacza „lepszy”. Mniej porównań? Mniej kodu? Optymalne porównania?
Teraz, gdy pytasz o czytelność kodu (biorąc pod uwagę poprawność), dokonałbym tylko jednej zmiany w twoim kodzie dla czytelności: Dopasuj pierwszy test do pozostałych.
Osobiście napisałbym to w następujący sposób, ale może to być zbyt niekonwencjonalne dla twoich standardów kodowania:
Przypis: Oto kod C ++ do generowania permutacji:
Edycje: Na podstawie opinii, przeniesiono TL: DR na górę, usunięto nieposortowaną tabelę, wyjaśniono 27, wyczyściłem kod, opisałem niemożliwe stany.
źródło
@msw powiedział ci, abyś użył tablicy zamiast a, b, c, a @Basile powiedział ci, aby przełożyć logikę „max” na funkcję. Połączenie tych dwóch pomysłów prowadzi do
następnie podaj funkcję, która oblicza maksymalny indeks dowolnej tablicy:
i nazwać to tak
Wydaje się, że całkowita liczba LOC wzrosła w porównaniu z pierwotną, ale teraz masz podstawową logikę w funkcji wielokrotnego użytku, a jeśli możesz wielokrotnie użyć tej funkcji, zacznie się to opłacać. Co więcej,
FindStrictMaxIndex
funkcja nie jest już powiązana z twoimi „wymaganiami biznesowymi” (oddzielenie problemów), dlatego ryzyko, które będziesz musiał zmodyfikować później, jest znacznie niższe niż w oryginalnej wersji (zasada otwartego zamknięcia). Na przykład ta funkcja nie będzie musiała zostać zmieniona, nawet jeśli liczba argumentów ulegnie zmianie, lub będzie trzeba użyć innych zwracanych wartości niż MOSTLY_ABC, lub jeśli przetwarzane są inne zmienne niż a, b, c. Ponadto użycie tablicy zamiast 3 różnych wartości a, b, c może uprościć kod również w innych miejscach.Oczywiście, jeśli w całym twoim programie jest tylko jedno lub dwa miejsca do wywołania tej funkcji i nie masz żadnych innych aplikacji do przechowywania wartości w tablicy, prawdopodobnie zostawiłbym oryginalny kod w takiej postaci, w jakiej jest (lub użyj @ poprawa rdzeni).
źródło
FindStrictMaxIndex()
mogą nie być zbyt czyste, ale z punktu widzenia dzwoniącego jest dość oczywiste, co próbuje się osiągnąć.int
funkcja pisania na klawiaturze. Ale zgadzam się na twój komentarz, jeśli używa się innego języka, takiego jak Python lub Perl.FindStrictMaxIndex
można ponownie użyć tej funkcji. W przypadku jednego lub tylko dwóch powtórzeń, to się nie opłaca, ale o tym już pisałem w odpowiedzi. Zwróć też uwagę na inne zalety, o których wspomniałem powyżej, dotyczące przyszłych zmian.return result[FindStrictMaxIndex(val,3)];
w punkcie kodu, w którym zostały umieszczone oryginalne 8 wierszy . Pozostałe części, a zwłaszczaFindStrictMaxIndex
sama w sobie, są całkowicie oddzielone od „logiki biznesowej”, która odsuwa je od centrum zmieniających się wymagań biznesowych.Prawdopodobnie powinieneś użyć makra lub funkcji
MAX
podającej maksymalnie dwie liczby.Więc po prostu chcesz:
Mogłeś zdefiniować
ale
MAX(i++,j--)
zachowaj ostrożność - szczególnie przy skutkach ubocznych - podczas korzystania z makr (ponieważ zachowywałby się dziwnie)Więc lepiej zdefiniuj funkcję
i użyj go (lub przynajmniej
#define MAX(X,Y) max2ints((X),(Y))
...)Jeśli chcesz zrozumieć pochodzenie MAX, możesz mieć długie makro,
#define COMPUTE_MAX_WITH_CAUSE(Status,Result,X,Y,Z)
które może być długimdo{
...}while(0)
makroNastępnie możesz wywoływać
COMPUTE_MAX_WITH_CAUSE(status,res,a,b,c)
w kilku miejscach. To jest trochę brzydkie. I zdefiniowane zmienne lokalnex
,y
,z
aby obniżyć złych skutków ubocznych ....źródło
Zastanowiłem się nad tym, więc ponieważ mój problem był głównie wizualnym potwierdzeniem, że wszystkie porównania wykorzystują te same zmienne, myślę, że może to być przydatne podejście:
Że każde makro trwa
a
,b
ic
w tej samej kolejności jest łatwe, aby potwierdzić, a nazwa makra oszczędza mi mający wypracować co wszystkie porównania i łączeniu robią.źródło