ArrayList vs LinkedList - ankieta

ArrayList vs LinkedList - ankieta
Nie wiem jaka jest różnica
4%
4% [2]
Nie zetknąłem się z sytuacją kiedy miało to praktyczne znaczenie
46%
46% [24]
Pamiętam pojedyncze sytuacje, kiedy miało to praktyczne znaczenie
42%
42% [22]
Często muszę optymalizować kod, wybierając jedną z implementacji List
8%
8% [4]
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 7 godzin
  • Postów:3277
0

Wiemy, że to podstawowe pytanie na rozmowie rekrutacyjnej. Dla programistów Java wręcz katechizm. W związku z tym ankieta

--edit
Pojawiły się wątpliwości co do sensu tych pytań.
Nie pytam o to, czy jest różnica, czy moga wystąpić hipotetyczne sytuacje, kiedy to ma znaczenie. Pytam o to, czy w swojej praktyce zetknęliście się z sytuacją, kiedy to faktycznie miało praktyczne znaczenie, czyli wpływało istotnie na wydajność, lub funkcjonalność aplikacji.

Pytam dlatego, że to jedne z pierwszych pytań na większości rozmów kwalifikacyjnych o Java.

edytowany 2x, ostatnio: piotrpo
stivens
Co jest hipotetycznego w pracy z AI? Ja np. AI to tylko hobbystycznie a nie zawodowo, wiec musze zaznaczyc "pojedyncze sytuacje" ale ktos moze zaznaczyc, ze "czesto". I co z tego wynika?
stivens
Chociaz dobra, chyba widze. Rekrutacja do CRUDa a pytanie o nieznaczaca w tym przypadku optymalizacje :)
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
7

W praktyce takie listy mają po kilka elementów i nie widziałem nigdy sytuacji żeby miało to jakiekolwiek znaczenie. Już prędzej bym rozkminiał HashMap vs TreeMap bo częściej można się spotkać z dużą mapą w pamięci jako jakiś cache


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Laska, z Polski
  • Postów:10056
1

No prosta sprawa, tam gdzie byś użył array'a jako kolekcji używasz ArrayList, a tam gdzie by Ci się chciał pisać listę jednokierunkową to LinkedList.

Twoja ankieta właściwie jest tożsama z ankietą: "Używasz array'ów czy list jednokierunkowych dwukierunkowych?".

edytowany 2x, ostatnio: Riddle
piotrpo
Próbuję dojść do tego, czy dla pisanych przez nas arcydzieł ma to praktyczne znaczenie (typu "aplikacja działa zauważalnie szybciej")
Riddle
@piotrpo: Jeśli zmiana implementacji z array'a na listę jednokierunkową mogłaby tu pomóc; np w przypadku kiedy większosć Twojego overheada to jest usuwanie elementów ze środka kolekcji, to tak. W przeciwnym wypadku taka zmiania nic nie da.
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Przecież LinkedList jest dwukierunkowa.
dokumentacja


edytowany 1x, ostatnio: scibi_92
Zobacz pozostałe 2 komentarze
Riddle
@Charles_Ray: Nie sądzę. Umiejętność programowania jest dużo ważniejsza niż zapamiętania jaka implementacja, w jakim języku i w jakiej bibliotece jest dwukierunkowa, a jaka jednokierunkowa. Mógłbym to sprawdzić w kilka sekund gdybym chciał.
Charles_Ray
Każdy tak mówi! ;) żartuje - wiem o co chodzi. Niestety kanon rekrutacji jest jaki jest
Riddle
@Charles_Ray: U mnie nie. Ja reviewuje jak człowiek :D Jakbyś przyszedł do nas do firmy na interview to nikt by Ci binary tree ani reverse polish notation pisać nie kazał.
Riddle
@Charles_Ray: I pytania czym się różni zbiór od listy też byś nie dostał.
S9
Tak szczerze to byłoby dziwne gdyby użyli jednokierunkowej. Jednokierunkowa jest dobra tylko w przypadku efektywnie niemutowalnych.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 7 godzin
  • Postów:3277
0

@TomRiddle: Ja wiem czym się różnią te implementacje, jakie są teoretyczne przypadki użycia A, lub B. Moja niewyartykułowana teza, to że dość rzadko zdarza się sytuacja kiedy liczba elementów w takich listach i scenariusz operacji ma jakiekolwiek znaczenie.

@jarekr000000: Inne implementacje List, własne/zewnętrzne .collections, czy nie używasz kolekcji?

Riddle
Administrator
  • Rejestracja:prawie 15 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Laska, z Polski
  • Postów:10056
0
piotrpo napisał(a):

@TomRiddle: Ja wiem czym się różnią te implementacje, jakie są teoretyczne przypadki użycia A, lub B. Moja niewyartykułowana teza, to że dość rzadko zdarza się sytuacja kiedy liczba elementów w takich listach i scenariusz operacji ma jakiekolwiek znaczenie.

No tak, dosyć rzadko.

Ale to jest pytanie bardziej o zasadnoć array vs lista dwukiernunkowa.

jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
2

Sorry - skasowałem post, bo stwierdziłem, że w sumie mogę olać ankietę. Ale się wypowiem.

Nie używam w normalnym kodzie żadnej z nich (99% przypadków).
Jeśli już w javie/kotlinie to vavro.io.collection.List albo vavr.io.collection.Vector

Javowe kolekcje są tragiczne, bo mutowalne i mają powalone api (metoda add zwracająca void i rzucająca exceptionem to moje ulubione).

W praktyce spotkałem sie z kodem gdzie jakby ktoś wstawił LinkedList zamiast ArrayList to byłoby średnio, ale ponieważ programista Javy zwykle używa ArrayList więc problemu sie nie spotyka. Odwrotna sytuacja jest możliwa, ale na tyle nietypowa, że nie pamiętam żebym kiedykolwiek widział (ale mogłem zapomnieć).


jeden i pół terabajta powinno wystarczyć każdemu
stivens
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 godziny
2

Przeciez to troche zalezy od tego co kto programuje. W biznesowym korpo kodzie gdzie listy maja po 5-15 elementow i nic ambitnego sie z nimi nie robi no to whatever. Ale przy pisaniu jakiegos AI te optymalizacje juz maja znaczenie.


λλλ
piotrpo
rozszerzyłem pierwszy post
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4707
3

@stivens pech polega na tym, że w kodzie gdzie to ma znaczenie i tak zwykle schodzi się na tablice prymitywów :-) (dokładnie zresztą w AI na javie).


jeden i pół terabajta powinno wystarczyć każdemu
Zobacz pozostałe 2 komentarze
jarekr000000
@YetAnohterone: 1. java jest dość niskopoziomowa, jak operujesz na tablicach to dasz radę zrobić kod zbliżony do tego z c (włączając vector api). 2. Jak potrzebujesz czegoś w stylu obliczenia na GPU to tablice javowe się używa (do wymiany przez JNI) (tu jest pole do poprawy, albo już poprawili w nowych jvm - nie wiem).
YA
Nawet, jeżeli się da, to czy zwykły klepacz kodu to ogarnie? Czy to nie jest raczej zadanie dla ogarniających prockowe niuanse domain expertów? I czy wobec tego takie high performance kolekcje nie powinny być wyrzucone do biblioteki, której zwykły klepacz kodu nie ma prawa się tykać?
jarekr000000
@YetAnohterone: to niezależna sprawa. Po to się robi biblioteki, żeby zwykły klepacz kodu nie musiał ogarniać, tylko korzystał. A to, że te biblioteki javowe - potem rypią sobie kod na tablicach (wspomaganych czasem przez wywołania JNI) to inna kwestia.
YA
OK, dotarło, dzięki.
KR
java jest dość niskopoziomowa, jak operujesz na tablicach to dasz radę zrobić kod zbliżony do tego z c (włączając vector api). Jeśli definicja "zbliżony" to typowo 1,5x - 3x wolniej to tak. Kompilatory JVMów, zwłaszcza tych darmowych jak OpenJDK, nie są tak mocne w generowaniu optymalnego kodu jak kompilatory C (gcc, clang). Czyli taka niskopoziomowa Java łączy ergonomię C z wydajnością Javy - zgadzam się, że takie coś lepiej zamykać w bibliotekach.
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:3 miesiące
  • Postów:205
4

Jeśli piszesz np. parser i nie wiesz ile elementów masz do sparsowania (a musisz je zapamiętywać), to wtedy warto wiedzieć, że lepiej użyć LinkedList . Według mnie ważniejsza od samej znajomości tego jak te struktury są zbudowane jest umiejętność określenia w jakich sytuacjach konkretna implementacja będzie lepsza.

Co do samej LinkedList to osobiście miałem sytuację, gdzie legacy aplikacja robiła cache "sesji" który potrafił spuchnąć do 30GB heapa - po zmianie implementacji na BitSet zużycie nie przekraczało 4GB :)

Wibowit
Jeśli piszesz np. parser i nie wiesz ile elementów masz do sparsowania (a musisz je zapamiętywać), to wtedy warto wiedzieć, że lepiej użyć LinkedList - przecież array lista się sama rozszerza w miarę potrzeb
damianem
no właśnie, tylko jeśli się rozszerza to musi przekopiować elementy ze starej tablicy do nowej - jeśli zależy Ci na czasie to nie jest optymalna sytuacja
Wibowit
robiłeś benchmarki? kopiowanie referencji jest bardzo szybkie. cały myk w tym, że to się amortyzuje i taki zamortyzowany koszt kopiowania to O(1) per wstawiany element.
KR
@damianem: Kopiowanie całości log N razy jest sumarycznie znacznie szybsze niż alokacja nowego bloku N razy. Użycie listy łączonej ma sens tylko wtedy jak musisz wstawiać / usuwać na początku lub środku listy bez zmiany kolejności elementów.
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
0

Domyślnie używałem ArrayList bo są szybsze przy odczycie. Nigdy nie spotkałem kodu gdzie LinkedList byłoby szybsze.

BTW ciekawa jest sytuacja gdy ma się niemutowalne listy. Tam naprawdę trzeba wybrać dobrą. I widać to już nawet na łańcuchach znaków w Haskellu


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
SL
  • Rejestracja:około 7 lat
  • Ostatnio:około 3 godziny
  • Postów:876
0

Twoja ankieta właściwie jest tożsama z ankietą: "Używasz array'ów czy list jednokierunkowych dwukierunkowych?".

@TomRiddle: niekoniecznie. Większość dobrych przykładów użycia linked list jakie znam używa intrusive lists (np http://www.davidespataro.it/kernel-linux-list-efficient-generic-linked-list/). Uproszczonym Javowym odpowiednikiem byłoby:

Kopiuj
class E {
// some data here
  E next;
}

"Opakowane" kontenery nie mają wielu zalet, które są szczególnie uwydatione, gdy używa się list jednokierunkowych np. operacje atomic albo "multikontenery": takie hybrydy, gdzie element jest w wielu kontenerach na raz, w porównaniu do np. LinkedHashSet to nie jest zahardkodowany ulep, tylko dowolna kompozycja

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 7 godzin
  • Postów:3277
0

@KamilAdam: Dlaczego w przypadku niemutowalnych kolekcji ma znaczenie jaka implementacja została wybrana?

S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Dlatego że jak masz LinkedList to możesz to niej preapendowac łatwo. W przypadku gdy masz kolekcję opartą o tablice musisz kopiować całą tablicę i dodawać


edytowany 3x, ostatnio: scibi_92
jarekr000000
Tej prezentacji, z tego dnia nie polecam. Grzesiek jest masterem w temacie, ale dokładnie wtedy trochę się poplątał, miał gorszy dzień i jest parę drobnych bzdur (z tego co pamiętam).
S9
zmieniłem xD
Wibowit
@scibi_92: w tym czymś możesz prependować, a jest tablicą pod spodem: https://docs.oracle.com/javase/8/docs/api/java/util/ArrayDeque.html
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
1
piotrpo napisał(a):

@KamilAdam: Dlaczego w przypadku niemutowalnych kolekcji ma znaczenie jaka implementacja została wybrana?

Bo są dramatyczne różnice przy modyfikacji kolekcji niemutowalnych. Załóżmy że chcesz dodać lub odjąć element z listy niemodyfikowalnej:

  • W przypadku niemutowalnego Vector musisz przepisać wszystkie elementy (ale za to jest najszybszy do odczytu) to bardziej skompilowane. Usuwanie jest w czasie O(1), ale dodawanie w czasie O(n)
  • W przypadku klasycznej listy linkowanej List możesz swobodnie dodawać i usuwać elementy, ale tylko od strony głowy. Działa dobrze jako stos, ale jak chcesz coś głębiej zmieniać to jest to liniowe do indeksu
  • W przypadku DList (i prawdopodobnie FMList) możesz swobodnie dodawać z obu stron, ale usuwanie jest kosztowne
  • W przypadki Sequence możesz robić modyfikacje ze stałym czasem log n. Prawdopodobnie pod spodem to są drzewa, ale nie sprawdzałem implementacji

Więcej implementacji nie znam :D


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 4x, ostatnio: KamilAdam
Zobacz pozostałe 11 komentarzy
Charles_Ray
A nawet bitmap-trie, muszę z ciekawości doczytać o tej implementacji.
piotrpo
No dobra, ale nadal, jeżeli masz kolekcje niemutowalne, to takie operacje jak wstawienie/usuwanie rekordu nie mają żadnego znaczenia, bo liczy się szybkość tworzenia nowej kolekcji i szybkość odczytu wg. jakiegoś tam scenariusza. Pomijam wykorzystanie pamięci.
KamilAdam
Jak masz klasyczną linked listę niemutowalą to czas tworzenia nowej kolekcji przy dodawaniu od przodu wynosi O(1), jest to czas dodania nowego elementu z przodu. Dodatkowa pamięć nie jest używana. Używana jest tylko pamięć na nowy element. Cała reszta jest współdzielona. Żadna cześć starej listy nie jest przepisywana
jarekr000000
@piotrpo: operacje wstawiania/usuwania mają jak najbardziej znaczenie.
stivens
@piotrpo: rzucam haslem persitent data structures a Ty nie sprawdzasz co to znaczy tylko piszesz o swoich wyobrazeniach jak takie niemutowalne struktury wygladaja :)
CE
  • Rejestracja:około 4 lata
  • Ostatnio:około 3 lata
  • Postów:48
1

A czy w przypadku ArrayList pamięć nie jest ciągła? Bo jeśli tak to będzie wielokrotnie szybsza przez ograniczenie zjawiska cache miss.

enedil
Niby +1, ale też -1, bo w sumie to jaka różnica, jeśli obiekty na tej liście będą i tak wskaźnikami. Chyba, że taka lista jest tylko lokalna dla jakiejś funkcji i escape analysis wykazało że nie ucieka, i da się jakoś zinlinować trzymane w niej obiekty.
CE
Cache line ma 64 bajty, jeżeli użyjesz pierwszego wskaźnika to cachujesz 8 wskaźników i 64 bajty w miejscu na które wskazuje. Nawet jeśli coś nakłamałem to benchamarki to potwierdzają :D
enedil
Hmm, prawda. Jestem przyzwyczajony do C++ i nie mam intuicji jak to działa jak mamy więcej poziomów indyrekcji
W0
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 2 godziny
  • Postów:3553
1

Ostatnio dosyć często korzystam z dużych kolekcji i praktycznie zawsze muszę mieć optymalizację na względzie. Koniec końców wygląda to tak, że w 90% przypadków wybieram albo tablicę, albo ArrayList (jeśli to typ prymitywny to coś z Trove). Używanie LinkedList ma sens tylko i wyłącznie wtedy, kiedy chcesz się bawić w modyfikację istniejących kolekcji - przy przetwarzaniu większych ilości danych jednak rzadko trzeba modyfikować kolekcje na żywca.

GS
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Postów:1265
0

Ja mam właśnie taką sytuację gdy typ listy ma znaczenie.
Korzystam z biblioteki JTS do tworzenia geometrii, i tam sobie wymyślono że można stworzyć geometrię tylko z tablicy Coordinates[] (https://locationtech.github.io/jts/javadoc/org/locationtech/jts/geom/GeometryFactory.html). I o ile taką tablicę robi się dość prosto z ArrayList metodą toArray, pewnie dlatego że w obu przypadkach pamięć jest liniowa, to już z generycznej Listy się nie da i trzeba robić kopię całej listy.

Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:22 minuty
3

myślę, że List.toArray w javce zawsze kopiuje całą tablicę


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 7 godzin
  • Postów:3277
0

@KamilAdam:

Jak masz klasyczną linked listę niemutowalą to czas tworzenia nowej kolekcji przy dodawaniu od przodu wynosi O(1), jest to czas dodania nowego elementu z przodu. Dodatkowa pamięć nie jest używana. Używana jest tylko pamięć na nowy element. Cała reszta jest współdzielona. Żadna cześć starej listy nie jest przepisywana

Albo inaczej rozumiemy niemutowalność, albo ja nie rozumiem jak działa LinkedLista :)
Szybka implementacja w Java:

Kopiuj
class MyLinekdList<T>{
  Item<T> firstItem;
  public MyLinkedList(List<T> elements){
    elements.forEach(e -> MyLinkedList::addElement(e);
  }
  private void addElement(T element){
    firstItem = new Element(element, firstItem);
  }

private class Item<T>{
  T element;
  Item<T> nextItem;
  Item(element, item){
    this.element = element;
    this.item = item;
  }
}

Elementy listy nie będą oczywiście kopiowane, bo przenoszone są jedynie referencje, ale cała struktura, w której przechowywane są te elementy (Item) jest jednak tworzona od początku i jakąś tam pamięć zajmuje.

edytowany 1x, ostatnio: piotrpo
jarekr000000
Cytując klasyka: co to k...a jest? Jak lista niemutowalna to nie wygląda to na pewno. Pomijając zamieszanie Item vs Element
SL
Ta lista jest niemutowalna, jeśli mówimy o List<T> bo ten MyLinekdList wygląda jak przekombinowany sposób na przemapowanie javowej listy na tą. Oczywiście, jak założymy, że T jest niemutowalne i nikt nie dobiera się do nextItem
Wibowit
no brakuje finali (i innych zmian) do niemutowalności, ale śmieszniejsze jest to, że konstruktor MyLinkedList odwraca wejściową listę
piotrpo
Pisałem na kolanie.... jako przykład do konkretnego stwierdzenia zawartego w poście. Nawet nie wiem, czy się kompiluje. Nadal nie mam pojęcia, jak można zmienić zawartość kolekcji niemutowalnej, do postaci innej kolekcji niemutowalnej, współdzieląc zarazem strukturę w której są przechowywane referencje do elementów tej listy.
Wibowit
przecież sam napisałeś prependa (addElement) w czasie O(1), który de facto tworzy nową listę na bazie poprzedniej, jeśli założymy, że (kiepsko nazwana) klasa Item reprezentuje listę. zajrzyj do przykładu, który nie jest pisany na kolanie: ArrayList vs LinkedList - ankieta
Schadoow
  • Rejestracja:około 13 lat
  • Ostatnio:około 7 godzin
  • Postów:1067
0

Kto nigdy nie dostał outofmemory na copy w arrayliście na produkcji niech pierwszy rzuci kamień xD.
Niestety randomowość wybierania przez deweloperów implementacji często powoduj dużo problemów w przewidywalności różnego rodzaju bibliotek.

Zobacz pozostałe 9 komentarzy
piotrpo
Jeżeli biblioteka działa różnie w zależności od tego jaka implementacja listy zostaje jej podana, to chyba trochę nie warto używać tej biblioteki.
Wibowit
w sensie biblioteka ma w jakiś magiczny sposób niwelować różnice w charakterystykach implementacji list? trochę nie rozumiem zarzutu. zbyt lakonicznie napisałeś.
piotrpo
Jeżeli masz doSomething(List<T> data) to metoda powinna działać, niezależnie od tego jaką implementację tam podasz. Jak powinna działać tylko na ArrayList, bo coś tam, to powinna mieć w sygnaturze ArrayList, a nie List. Drugi komentarz o pamięci - niby LL ma wyższy narzut, ale nie zawsze - spora część tablic w AL może być niewykorzystana. Inna sprawa, że nie narzut pamięci listy (tej, czy innej) jest raczej znikomy w porównaniu do tego co tam jest przechowywane.
Wibowit
zrobiłem już rozpiskę o narzucie AL vs LL i AL generalnie wygrywa. jeśli twierdzisz inaczej to zrób benchmark jakiś. same metody wspomniane przez @Schadoow powinny działać dobrze z obiema implementacjami, ale narzut pamięciowy sprawia, że w różnych momentach brakuje pamięci. ten brak dostępnej pamięci jest moim zdaniem tutaj głównym problemem.
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
8

@piotrpo: tylko że tak nie wygląda funkcyjna, niemutowalna linked lista :D
Funkcyjna niemutowalna linked lista wygląda tak List.
Z czego najważniejsze jest List.Nil czyli pusta lista i List.Cons czyli komórka do dodawania nowego elementu na początek.

Fragmenty implementacja w Javie z Vavr

Kopiuj
//Komórka Cons
private Cons(T head, List<T> tail) {
        this.head = head;
        this.tail = tail;
        this.length = 1 + tail.length();
    }

//Dodanie nowego elementu na początek, stara lista się nie zmienia ani nie jest przepisywana
@Override
  public final List<T> prepend(T element) {
      return new Cons<>(element, this);
  }

//Utworzenie listy jednoelementowej to dodanie elementu do pustej list
public static <T> List<T> of(T element) {
      return new Cons<>(element, Nil.instance());
  }

A tutaj ładny obrazek współdzielenia list niemutowalnych
list


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 1x, ostatnio: KamilAdam
Zobacz pozostałe 2 komentarze
jarekr000000
W ogóle zrobienie swojej listy (ale takiej jak wyżej - dobrej) i podstawowych operacji to taka Kata, którą warto sobie robić. Potem odwracanie, sortowanie, wydajna (amortyzowana) kolejka itp. Jest dużo fajnych niuansów, a kod wychodzi ładny. No chyba, że zrobimy to w javie - wtedy wychodzi taki sobie (choć ćwiczenie jest nadal godne).
vpiotr
Osobna kategoria katy to zrobienie tego bjutiful w ugly języku. Od siebie dodam ćwiczenia: wyszukiwanie binarne i wynajdowanie cykli.
jarekr000000
@vpiotr: zastanawiam się jak zrobić cykl w takiej liście (o ile nie przerobimy na leniwą).
vpiotr
cykl w prawilnej raczej się nie da, algorytm dotyczy albo grafu skierowanego albo uszkodzonej listy.
jarekr000000
Zrobienie lazy list jest fajnym ćwiczeniem - można pojechać w naprawdę dziwne rozwiązania (np. lista wszystkich liczb nieparzystych od której odejmujemy wszystkie pierwsze i jedziemy).
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:4 dni
  • Lokalizacja:Silesia/Marki
  • Postów:5505
2
GutekSan napisał(a):

I o ile taką tablicę robi się dość prosto z ArrayList metodą toArray, pewnie dlatego że w obu przypadkach pamięć jest liniowa, to już z generycznej Listy się nie da i trzeba robić kopię całej listy.

Wibowit napisał(a):

myślę, że List.toArray w javce zawsze kopiuje całą tablicę

Post Wibowita w stylu niszczymy dzieciństwo :P
I pewnie znów ma rację :D

ArrayList:

Kopiuj
public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

Arrays:

Kopiuj
   @SuppressWarnings("unchecked")
   public static <T> T[] copyOf(T[] original, int newLength) {
       return (T[]) copyOf(original, newLength, original.getClass());
   }

  @HotSpotIntrinsicCandidate
  public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
      @SuppressWarnings("unchecked")
      T[] copy = ((Object)newType == (Object)Object[].class)
          ? (T[]) new Object[newLength]
          : (T[]) Array.newInstance(newType.getComponentType(), newLength);
      System.arraycopy(original, 0, copy, 0,
                       Math.min(original.length, newLength));
      return copy;
  }

Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
edytowany 2x, ostatnio: KamilAdam
Zobacz pozostałe 4 komentarze
KamilAdam
Hm, czyli kopiowanie całej tablicy, nierówna kopiowaniu całej tablicy
Wibowit
gdyby toArray zwracało wewnętrzną tablicę to byłoby to dość błędogenne. np: var niemutowalnaArrayLista = Collections.unmodifiableList(Arrays.asList("ala", "ma", "kota")); niemutowalnaArrayLista.toArray()[0] = "haha, przechytrzyłem system bez refleksji"; można też wymyślić inne przykłady, np. robienie toArray na lokalnej liście (wcześniej sprawdzonej, że jest bezpieczna) i wrzucanie wynikowej tablicy do niekoniecznie bezpiecznych metod.
jarekr000000
@KamilAdam: w tym przypadku nawet bardzo. L1 nie kocha naszych funkcyjnych wynalazków, nie kocha javowej LinkedList i nie kocha nawet javowych tablic (ciągle) (no chyba, że są na prymitywach).
KamilAdam
L1 nie kocha naszych funkcyjnych wynalazków to ja wiem (ale nie zawsze pamiętam). Słuchałem "narzekania" Jarosława Pałki na programistów funkcyjnych i na to że zapominają że jeszcze nie ma funkcyjnych procesorów :D
jarekr000000
@KamilAdam: tu trzeba pamiętać, że w wiekszości naszych programów i tak to nie CPU po stronie javy jest problemem. A nawet jak jest, to niekoniecznie funkcyjne struktury danych mają wpływ. A nawet jak mają wpływ to niekoniecznie tam gdzie się spodziewamy - czyli np. przetwarzanie idzie dość sprawnie .... i dopiero w "procesie" GC zaczyna się problem.
SN
  • Rejestracja:prawie 19 lat
  • Ostatnio:3 miesiące
0

Ja widziałem jak do listy było wstawiane kilkaset unikalnych elementów i później wyszukiwanie w tej liście liniowo (wyszukiwanie z kilkudziesięciu różnych miejsc) :)
Jak robiłem review tego kodu to się dowiedziałem od jednego z programistów, że użycie Set w tej sytuacji to premature optimization :)
Programista, który to pisał nie znał różniczy między ArrayList, LinkedList a o Set nie słyszał.
Tak więc podążając dalej tym tropem można zadać kolejne pytanie.
Czy wiesz jak utworzyć tablicę w Javie?
Ile razy tworzyłeś tablicę w Javie?
Czy to że nie wiesz jak utworzyć tablicę w Javie ma znaczenie?
Nie martw się, to że nie wiesz jak utworzyć tablicę w Javie nie ma znaczenia.
Kogo by to obchodziło, zawsze można przecież doczytać, nauczysz się w pracy.

edytowany 5x, ostatnio: snakeomeister
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:22 minuty
0

@snakeomeister: ja widziałem jak koledzy z zespołu robili coś równie nieoptymalnego, ale nieco mniej oczywistego, czyli odpalanie metody def find(p: (A) => Boolean): Option[A] na Secie. to jest liniowa operacja, bo taka funkcja (tzn. p: (A) => Boolean) nie pozwala na szybkie wybranie elementu ze zbioru. wynik jest taki sam - liniowe przechodzenie przez kolekcję zamiast szybkiego lookupu.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 4x, ostatnio: Wibowit
jarekr000000
Sam find na secie to nic złego. Dopiero find( x ==_) i tym podobne jest średni.
Wibowit
eee. zamiast robić val set = cośtam; for (...) { set.find(_.field == x) ... } można zrobić val map = cośtam.map(x => x.field -> x).toMap; for (...) { map.get(x) ... }
SN
  • Rejestracja:prawie 19 lat
  • Ostatnio:3 miesiące
1
Wibowit napisał(a):

@snakeomeister: ja widziałem jak koledzy z zespołu robili coś równie nieoptymalnego, ale nieco mniej oczywistego, czyli odpalanie metody def find(p: (A) => Boolean): Option[A] na Secie. to jest liniowa operacja, bo taka funkcja (tutaj: p) nie pozwala na szybkie wybranie elementu ze zbioru. wynik jest taki sam - liniowe przechodzenie przez kolekcję zamiast szybkiego lookupu.

Tak też można :) Ogólnie chodzi mi o to, że widzę taki trend, że wszystkie pytania na rozmowach są bez sensu i po prostu mnie zatrudnijcie ja jestem super programistą, który nie zna różnicy między ArrayList a LinkedList, ale chcę 15k na rękę, bo mam bardzo dobre soft skille :)

  1. Codility - nie bo z algorytmów się nie korzysta, kogo tam obchodzi jak zaimplementować jakiś głupi MergeSort
  2. Jakieś pytanie z frameworka z którego korzystamy w pracy - nie bo można znaleźć w internecie i to są w ogóle jakieś bezsensowne detale
  3. Zadanie praktyczne - nie bo nie będę tracić czasu

Ja się w takim razie pytam, jak kogoś można zrekrutować?
Na jakiej podstawie stwierdzić czy ktoś jest dobrym programistą czy nie?

edytowany 6x, ostatnio: snakeomeister
Wibowit
  • Rejestracja:prawie 20 lat
  • Ostatnio:22 minuty
4
snakeomeister napisał(a):
  1. Codility - nie bo z algorytmów się nie korzysta, kogo tam obchodzi jak zaimplementować jakiś głupi MergeSort
  2. Jakieś pytanie z frameworka z którego korzystamy w pracy - nie bo można znaleźć w internecie i to są w ogóle jakieś bezsensowne detale
  3. Zadanie praktyczne - nie bo nie będę tracić czasu

Ja się w takim razie pytam, jak kogoś można zrekrutować?
Na jakiej podstawie stwierdzić czy ktoś jest dobrym programistą czy nie?

Można poprosić o to, by wybrał jakiś projekt w którym pracował i opisał wyzwania w nim oraz rozwiązania, które stworzył dla tych problemów. Z zastrzeżeniem, że to ma być dialog - przepytywany coś tam opowiada, ale my (rekrutujący) dopytujemy o interesujące nas szczegóły i kwestie, w których jesteśmy na tyle mocni, żeby od razu wiedzieć czy koleś opowiada z sensem.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 1x, ostatnio: Wibowit
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 7 godzin
  • Postów:3277
1
snakeomeister napisał(a):

Tak też można :) Ogólnie chodzi mi o to, że widzę taki trend, że wszystkie pytania na rozmowach są bez sensu i po prostu mnie zatrudnijcie ja jestem super programistą, który nie zna różnicy między ArrayList a LinkedList, ale chcę 15k na rękę, bo mam bardzo dobre soft skille :)

Pytania na rozmowach są bez sensu, ale z trochę innych powodów:

  1. Codility - nie bo z algorytmów się nie korzysta, kogo tam obchodzi jak zaimplementować jakiś głupi MergeSort

Stres zmienia dużo. Zadania codility odrzucają sporą część kumatych kandudatów, a w rezultacie przechodzi ten, który najmniej się zdenerwował.

Jakieś pytanie z frameworka z którego korzystamy w pracy - nie bo można znaleźć w internecie i to są w ogóle jakieś bezsensowne detale

Nie jest totalnie bez sensu. Ma spore ryzyko, że zatrudnisz sprawnego klikacza. a nie dobrego inżyniera. Oczywiście zależy jeszcze, czy pytasz o @Autowire, czy np. o DynamicProxy

  1. Zadanie praktyczne - nie bo nie będę tracić czasu

To jest prawda, chociaż nie jest bez sensu. Zadania prarktyczne wymagają niestety dużo czasu po obu stronach

Dodam jescze, ze taki egzamin z podstaw Javy zaczynam uważać za również pozbawiony sensu, nawet nie ze względu na to, że wiedza o czym się różni ArrayList od LinkedList jest niepotrzebna, tylko pytają o to (i parę innych rzeczy) na wszystkich rozmowach, więc przechodząc zestaw 100 pytań rekrutacyjnych można wykuć odpowiedzi. I całkiem sporo kandydatów tak robi.

Ja się w takim razie pytam, jak kogoś można zrekrutować?
Na jakiej podstawie stwierdzić czy ktoś jest dobrym programistą czy nie?

I to jest bardzo dobre pytanie na wątek w dziale kariera. Pewnie punktem wyjścia jest "co to znaczy być dobrym programistą w twoim projekcie".

W tym wątku bardziej zastanawiałem się, skąd się bierze Javowy fetysz na kolekcje, bo z mojego doświadczenia przytłaczająca większość przypadków użycia to takie, gdzie do listy wrzucane jest 20 elementów, a wszystko co się z nimi robi to iterowanie po elementach, a wszystko opakowane w operacje o mega narzucie czasowym typu komunikacja http, a jak pojawiało się coś faktycznie wymagającego optymalizacji, to java.collections nie było w stanie pomóc.
Z drugiej strony jest to pytanie lecące zaraz po "dzień dobry" na 99% rozmów kwalifikacyjnych i chciałem sprawdzić, czy moja opinia jest podzielana przez innych, czy może horyzont kończy mi się na granicy mojego grajdołka.

SN
  • Rejestracja:prawie 19 lat
  • Ostatnio:3 miesiące
0

Pytania na rozmowach są bez sensu, ale z trochę innych powodów:

  1. Codility - nie bo z algorytmów się nie korzysta, kogo tam obchodzi jak zaimplementować jakiś głupi MergeSort

Stres zmienia dużo. Zadania codility odrzucają sporą część kumatych kandudatów, a w rezultacie przechodzi ten, który najmniej się zdenerwował.

Może właśnie o to chodzi, żeby znaleźć tych, którzy są na tyle dobrzy, że tego typu zadania ich nie stresują?
Nawet jeżeli znają rozwiązanie i nie rozwiązali tego tylko ze względu na stres, to może też znaczy że się nie nadają bo w pracy programisty jednak niekiedy stresu może być dużo?
Jeżeli takie zadanie rozwiązuje się live z kandydatem wtedy można też przy okazji sprawdzić techniki komunikacji.

Nie jest totalnie bez sensu. Ma spore ryzyko, że zatrudnisz sprawnego klikacza. a nie dobrego inżyniera. Oczywiście zależy jeszcze, czy pytasz o @Autowire, czy np. o DynamicProxy

Ok, tu się zgodzę :)

To jest prawda, chociaż nie jest bez sensu. Zadania prarktyczne wymagają niestety dużo czasu po obu stronach

Może warto wymyślać zadania, które rzeczywiście można rozwiązać w 2-4h?
Np. to samo co na codility/leetcode itp, tyle że wtedy pewnie jest duże ryzyko, że ktoś zrobi copy&paste.

Dodam jescze, ze taki egzamin z podstaw Javy zaczynam uważać za również pozbawiony sensu, nawet nie ze względu na to, że wiedza o czym się różni ArrayList od LinkedList jest niepotrzebna, tylko pytają o to (i parę innych rzeczy) na wszystkich rozmowach, więc przechodząc zestaw 100 pytań rekrutacyjnych można wykuć odpowiedzi. I całkiem sporo kandydatów tak robi.

Przynajmniej wykuwając odpowiedzi czegoś się nauczą :)

Z drugiej strony jest to pytanie lecące zaraz po "dzień dobry" na 99% rozmów kwalifikacyjnych i chciałem sprawdzić, czy moja opinia jest podzielana przez innych, czy może horyzont kończy mi się na granicy mojego grajdołka.

Odpowiadając na to pytanie to mi się przytrafiły kilka(naście) razy tego typu sytuacje, gdzie to miało znaczenie, więc chyba nie za dużo.

Imho taką różnicę moim zdaniem trzeba znać, niezależnie od tego ile razy to ma realne zastosowanie, bo jest to dosyć podstawowa wiedza.

edytowany 7x, ostatnio: snakeomeister
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)