Pytanie jaki jest sens heterogenicznych tablic?


Wiem, że języki bardziej dynamiczne niż Java, takie jak Python i Ruby, często umożliwiają umieszczanie obiektów o różnych typach w tablicach, jak na przykład:

["hello", 120, ["world"]]

Nie rozumiem, dlaczego kiedykolwiek używałbyś takiej funkcji. Jeśli chcę przechowywać heterogeniczne dane w Javie, zwykle utworzę dla niego obiekt.

Na przykład powiedz a User ma int ID i String name. Chociaż widzę, że w Python / Ruby / PHP można zrobić coś takiego:

[["John Smith", 000], ["Smith John", 001], ...]

to wydaje się nieco mniej bezpieczne / OO niż tworzenie klasy User z atrybutami ID i name i mając swoją tablicę:

[<User: name="John Smith", id=000>, <User: name="Smith John", id=001>, ...]

gdzie te <User ...> rzeczy reprezentują obiekty użytkownika.

Czy istnieje powód, aby używać tego pierwszego z tych drugich w językach, które go obsługują? Czy istnieje jakiś większy powód do korzystania z heterogenicznych tablic?

N.B. Nie mówię o tablicach, które zawierają różne obiekty, które wszystkie implementują ten sam interfejs lub dziedziczą z tego samego rodzica, np .:

class Square extends Shape
class Triangle extends Shape
[new Square(), new Triangle()]

ponieważ to jest, przynajmniej dla programisty, wciąż jednolita tablica, ponieważ będziesz robił to samo z każdym kształtem (np. draw() metoda), tylko metody powszechnie zdefiniowane między tymi dwoma.


16
2017-12-26 16:47


pochodzenie


Python lub Ruby są dynamicznie pisane, więc heterogeniczne tablice są "wolne" do zaimplementowania. - Etienne de Martel
"to wydaje się nieco mniej bezpieczne"? Co masz na myśli przez "bezpieczny"? Należy zauważyć, że "bezpieczeństwo typu" jest bezwzględną gwarancją w Pythonie, ponieważ typ obiektu jest sprzężony z wartością w sposób, który nie może zostać cofnięty przez coś w rodzaju operacji rzutowania. Proszę określić, co masz na myśli przez "bezpieczne" w tym pytaniu. - S.Lott
Jednym z rodzajów bezpieczeństwa jest to, że błędy kodowania są wykrywane podczas kompilacji. A to jest coś, co jest dynamicznie wpisywane na klawiaturze. Języki nie mogą zawierać wielu błędów. Oczywiście zyskujesz elastyczność w zamian. - CodesInChaos
W jaki sposób program będzie zawierał coś podobnego, chyba że w pierwszej kolejności oświadczysz tego? - the Tin Man
Nie - mówię to, ponieważ popełniam błędy, będąc w stanie mieć obiekty z konstruktorem w formie ( (String) name, (int) id ) umożliwia językowi wysłanie błędu, gdy ktoś coś nieprawidłowo zakoduje, np. name, id, email. - Aaron Yodaiken


Odpowiedzi:


Jak pisał katrielalex: Nie ma powodu, aby nie wspierać heterogenicznych list. W rzeczywistości odrzucenie go wymagałoby statycznego pisania i wróciliśmy do tej starej debaty. Ale powstrzymajmy się od tego, a zamiast tego odpowiedzmy na pytanie "dlaczego miałbyś użyć tej części" ...

Szczerze mówiąc, nie jest używany że wiele - jeśli skorzystamy z wyjątku w twoim ostatnim akapicie i wybierzmy bardziej liberalną definicję "implementuj ten sam interfejs" niż np. Java lub C #. Prawie cały mój kod do iteracji-crunching oczekuje, że wszystkie elementy wdrożą jakiś interfejs. Oczywiście, że tak, w przeciwnym razie może zrobić bardzo mało!

Nie zrozumcie mnie źle, są absolutnie ważne przypadki użycia - rzadko istnieje dobry powód, aby napisać całą klasę dla zawarcia pewnych danych (a nawet jeśli doda się kilka kalorii, czasami przychodzi im na pomoc funkcjonalne programowanie). Dykta byłby jednak bardziej powszechnym wyborem, i namedtuple jest również bardzo schludny. Ale są mniej powszechne, niż myślisz, i są używane z myślą i dyscypliną, a nie z kodowaniem kowbojskim.

(Także Ty "User jako listę zagnieżdżoną "przykład nie jest dobry - ponieważ wewnętrzne listy mają stałą wielkość, lepiej używać krotek i to czyni je poprawnymi nawet w Haskell (typ byłby [(String, Integer)]))


4
2017-12-26 17:17



Jakie są te "absolutnie ważne przypadki użycia"? - Aaron Yodaiken
@aharon: Prawie za każdym razem, gdy pracują i są mniej kłopotliwe niż alternatywy. Na przykład, dyktuje z niejednorodnymi wartościami (pytanie dotyczy tablic, ale tak naprawdę jakakolwiek kolekcja może być heterogeniczna) tworzyć dobre lekcje. Heterogeniczne krotki / listy są mniej samo-dokumentujące i dlatego nie są tak wskazane, ale także ważne w zależności od danych (np. Zbyt mało danych używanych w zbyt małych miejscach, aby dyktować w sposób szczególny lepszy).


Zastosowanie a multimetr do tablicy może mieć jakiś sens. Przestawiasz strategię na bardziej funkcjonalny styl, w którym skupiasz się na dyskretnej części logiki (tj. Multimetodzie) zamiast na dyskretnym fragmencie danych (tj. Obiektach tablicy).

W twoim przykładzie kształtów zapobiega to konieczności definiowania i implementacji Shape berło. (Tak, to nie jest wielka sprawa, ale co by było, gdyby kształt był jedną z kilku superklas, które chciałbyś przedłużyć? W Javie, w tym momencie jesteś SOL.) Zamiast tego zaimplementujesz inteligentne draw()multimethod, który najpierw analizuje argument, a następnie wywołuje odpowiednią funkcję rysowania lub obsługę błędów, jeśli obiekt nie jest możliwy do rysowania.

Porównania między stylami funkcjonalnymi i obiektowymi są wszędzie; Oto kilka istotnych pytań, które powinny zapewnić dobry start: Programowanie funkcyjne a programowanie obiektowe i Wyjaśnianie programowania funkcjonalnego programistom obiektowym i osobom mniej technicznym.


4
2017-12-26 17:12



@Aararon Ostatni akapit dotyczący programowania funkcjonalnego vs obiektowego jest z korzyścią dla każdego, kto czyta tę odpowiedź w dół drogi. Nie sugeruję, że nie jesteś świadomy różnic. - G__


Czy jest powód, aby używać tego pierwszego   ten drugi w językach, które obsługują   to?

Tak, istnieje bardzo prosty powód, dla którego możesz to zrobić w Pythonie (i zakładam to samo w Ruby):

Jak sprawdzić, czy lista jest heterogeniczna?

  • Nie można po prostu porównać typów bezpośrednio, ponieważ Python ma pisanie kaczkami.
  • Jeśli cały obiekt ma jakiś typowy typ Python, również nie można tego odgadnąć. Wszystko popiera istnienie repri tak się nie zgadzali, więc powinieneś być w stanie umieścić je również na liście.
  • Nie ma sensu przekształcać list w tylko typ, który wymaga również deklaracji typu.

Po prostu nie ma sposobu, aby uniemożliwić stworzenie heterogenicznej listy!

Czy jest jakiś większy powód do użycia?   heterogeniczne tablice?

Nie, nie mogę o niczym myśleć. Jak już wspomniałeś w swoim pytaniu, jeśli korzystasz z heterogenicznych tablic, robisz rzeczy trudniejsze, niż muszą być.


3
2017-12-26 18:22





Nie ma powodu, aby nie wspierać heterogenicznych list. Jest to ograniczenie ze względów technicznych, a my ich nie lubimy.

Nie wszystko musi być klasą!

W Pythonie klasa jest w zasadzie zbuforowanym słownikiem z dodatkowymi dodatkami. Robiąc zajęcia User niekoniecznie jest jaśniejsze niż słownik {"name": ..., "id": ...}.


2
2017-12-26 16:51



Ale słownik nie może mieć dodatkowych metod, jeśli chcę je później rozszerzyć, prawda? - Aaron Yodaiken
Nie, ale jeśli chcesz dodatkowych metod, możesz podklasę dict. A to jest rozszerzalne; możesz wymieszać i dopasować słowniki do FunkyDictionaries i niestandardowe odwzorowania, pod warunkiem, że po uruchomieniu kodu dostępne są wszystkie wymagane metody. Zauważ również, że możesz mieć funkcje globalne (nie dołączone do klasy), więc na przykład możesz zdefiniować funkcję split_name = lambda d: d['name'].split() do zwracania pierwszych i ostatnich nazw, rozdzielanych białymi znakami. Ta funkcja nie musi być powiązana z dict klasa. - Katriel
@aharon: Jeśli chcesz niestandardowe metody, to znaczy prawdziwe zachowanie, klasa jest uzasadniona. Ale nie, jeśli chcesz tylko uporządkować niektóre dane i zastosować do nich przekształcenia - w tych (bardzo często) przypadkach klasa dodaje zero korzyści i zbyt wiele dodatkowych linii.


Nic nie stoi na przeszkodzie, aby mieć heterogeniczną tablicę w Javie. Jest uważany za kiepski styl programowania, a użycie właściwych POJO będzie szybsze / bardziej wydajne niż heterogeniczne tablice w Javie lub jakimkolwiek innym języku, ponieważ rodzaje "pól" są statycznie znane, a prymitywy mogą być używane.

W Javie możesz

Object[][] array = {{"John Smith", 000}, {"Smith John", 001}, ...};

1
2017-12-26 17:21





Listy erogenne są bardzo przydatne. Na przykład, aby stworzyć grę węża, mogę mieć listę takich bloków: [[x, y, "dół"], [x1, y1, "dół"]] zamiast klasy dla bloków i mogę uzyskać dostęp szybciej do każdego elementu.


0
2017-12-26 17:03



Jest to nadal jednorodna lista krotek (int, int, string). - Jochen Ritzel
ale int, int, string jest heterogeniczny. - pythonFoo
Nie pojmowałbym koncepcyjnie twojej wewnętrznej listy jako heterogenicznej listy, ale jako 3-krotną. Ale oczywiście w dynamicznie pisanych językach jest wspierany przez ten sam typ. Ale w statycznie napisanych językach można osiągnąć to samo z krotkami bez utraty (kompilacji) bezpieczeństwa typu. Nie jest to dobry przykład do pokazania, gdzie heterogeniczne listy są użyteczne, poza tym, co jest dostarczane w statycznie napisanych językach. - CodesInChaos
"i mogę uzyskać dostęp szybciej do każdego elementu." [wymagany cytat] - MatrixFrog
@MatrixFrog: pastebin.com/10DCvtuQ ten mały fragment na moim komputerze wyświetla: 6.58470416069 6.20616889 - pythonFoo


W Lua obiekt i tablica to to samo, więc przyczyna jest bardziej oczywista. Powiedzmy, że Lua ma słabe pisanie na klawiaturze

Poza tym miałem obiekt Map Google i musiałem usunąć wszystkie markery utworzone dotychczas na tej mapie. Więc stworzyłem tablicę dla markers, tablica dla circles i tablica dla places. Następnie wykonałem funkcję iteracji nad tymi trzema tablicami i wywołaniem .remove() na każdym z nich. Wtedy zdałem sobie sprawę, że mogę po prostu mieć jedną niejednorodną tablicę i wstawić do niej wszystkie obiekty i powtórzyć raz w tej tablicy


0
2018-05-15 18:56





Oto prosta odpowiedź:

N.B. Nie mówię o tablicach, które zawierają różne obiekty, które     wszystkie implementują ten sam interfejs lub dziedziczą z tego samego rodzica, np .:

Wszystko rozciąga java.lang.Object ... i tyle. Nie ma powodu nie mieć obiekt [] i umieścić wszystko, co lubisz. Obiekt [] jest wyjątkowo przydatny w każdym oprogramowaniu pośredniczącym, takim jak warstwa trwałości.


-1
2017-12-26 17:33



-1. Jeśli korzystasz z Javy, równie dobrze możesz skorzystać z sprawdzania poprawności czasu kompilatora. Każdy kod, który używa Object lub Object[] natychmiast podnosi w mojej głowie czerwoną flagę. - MatrixFrog