Usuwanie z kontenera - który sposób lepszy?

Usuwanie z kontenera - który sposób lepszy?
AB
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 10 lat
  • Postów:26
0

Chcę wywalić wszystko z deque(początkowo uzywalem vectora ale zdecydowalem sie na deque, czy to dobrze?) jednocześnie wykonując pewną operacje dla każdego z nich.
Wymyśliłem dwa sposoby, i zastanawiam się który jest lepszy.
(pseudokody)
Pierwsza część jest taka sama dla obydwu sposobów:

Kopiuj
std::deque<b2Body*> toDelete;
void setToDelete(b2Body* obj)
{
 bool ok(true);
    for(const b2Body* b: toDelete)
    {
        if(b == obj) // sprawdź czy wskaźnik już był dodany. inaczej będzie crash
        {
        ok = false;
        }
    }

    if(ok) {
    toDelete.push_back(obj);
    }
}

Na drugą cześć, gdzie usuwam, mam dwa sposoby:
Sposób 1

Kopiuj
 while(toDelete.empty())
    {
        world.DestroyBody(toDelete.back());
        toDelete.pop_back();
    }
  • Sposób 2**
Kopiuj
for(const b2Body* b : toDelete)
{
world.DestroyBody(b);
}
toDelete.clear();

Który sposób jest lepszy i dlaczego? + czy dobrze zrobiłem używając deque zamiast std::vector?

twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
1

Dodanie do tej tablicy (czy tam kolejki) jest nieefektywne, bo za każdym razem lecisz po całym kontenerze. Raczej używałbym czegoś w stylu std::set. Samo usuwanie to już pikuś, range for z auto wygląda ładniej (i powinno być szybsze), a clear raczej nie jest potrzebne.

Zabawa gołymi wskaźnikami trochę razi, choć w tym przypadku opakowanie tego w jakiś unique_ptr wygląda trochę jak przerost formy nad treścią.

edytowany 2x, ostatnio: twonek
gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
1
twonek napisał(a):

Dodanie do tej tablicy (czy tam kolejki) jest nieefektywne, bo za każdym razem lecisz po całym kontenerze. Raczej używałbym czegoś w stylu std::set. Samo usuwanie to już pikuś, range for z auto wygląda ładniej (i powinno być szybsze), a clear raczej nie jest potrzebne.

Zabawa gołymi wskaźnikami trochę razi, choć w tym przypadku opakowanie tego w jakiś unique_ptr wygląda trochę jak przerost formy nad treścią.

poznaj może najpierw std::deque, a potem kłam, że dodawanie jest nieefektywne; wszystko jest efektywne dopóki pracujesz na pierwszym lub ostatnim elemencie,

std::set wymaga zdefiniowanego operator< lub funkcji sortującej + sortuje co insert co czyni go milion razy mniej wydajnym od deque (jeżeli warunki są spełnione), pewnie miałeś na myśli unordered_set

edit:
sposób 2

edytowany 1x, ostatnio: gośćabc
twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0
gośćabc napisał(a):

poznaj może najpierw std::deque, a potem kłam, że dodawanie jest nieefektywne; wszystko jest efektywne dopóki pracujesz na pierwszym lub ostatnim elemencie,

To pokaż mi pierwszy i ostatni element w tym kodzie:

Kopiuj
for(const b2Body* b: toDelete)
{
    if(b == obj) // sprawdź czy wskaźnik już był dodany. inaczej będzie crash
    {
        ok = false;
    }
}
gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0
twonek napisał(a):
gośćabc napisał(a):

poznaj może najpierw std::deque, a potem kłam, że dodawanie jest nieefektywne; wszystko jest efektywne dopóki pracujesz na pierwszym lub ostatnim elemencie,

To pokaż mi pierwszy i ostatni element w tym kodzie:

Kopiuj
for(const b2Body* b: toDelete)
{
    if(b == obj) // sprawdź czy wskaźnik już był dodany. inaczej będzie crash
    {
        ok = false;
    }
}

a gdzie w tym kawałeczku masz modyfikację chlopaku, że tak mi cytujesz kod, który nie modyfikuje kontenera?

on tutaj tylko sprawdza czy już dodał ten wskaźnik, a pod spodem używa push_back, który nie invaliduje nic i działa świetnie z std::deque

edytowany 1x, ostatnio: gośćabc
twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0

Przy każdej operacji push_back leci po całym kontenerze. Może powiesz mi, że to jest efektywne?

gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0
twonek napisał(a):

Przy każdej operacji push_back leci po całym kontenerze. Może powiesz mi, że to jest efektywne?

to jest spieprzona logika a nie wina złego kontenera;

twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0
gośćabc napisał(a):
twonek napisał(a):

Przy każdej operacji push_back leci po całym kontenerze. Może powiesz mi, że to jest efektywne?

to jest spieprzona logika a nie wina złego kontenera;

No to teraz cytuj, gdzie napisałem, że to jest nieefektywne z winy kontenera?

gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0

Dodanie do tej tablicy (czy tam kolejki) jest nieefektywne,

edit:
już nic więcej nie pisz znawco, bo mi ciśnienie skoczyło

edytowany 1x, ostatnio: gośćabc
twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0
gośćabc napisał(a):

Dodanie do tej tablicy (czy tam kolejki) jest nieefektywne,
bo za każdym razem lecisz po całym kontenerze.

Umiesz czytać całe zdanie, czy tylko wybrane przez siebie fragmenty i bić pianę?

gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0

tak bo operacja push_back wymaga iterowania po całym kontenerze,

no z matołem gadam

twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0

A ja chyba z analfabetą. Piszę do autora lecisz po całym kontenerze, a nie operacja push_back leci po całym kontenerze. Widzisz różnicę?

gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0

ok to jeżeli poszedłem z rozumowaniem za daleko i powinienem odczytać to dosłownie, to co podmiana na set da?

g**no, tak jak całe Twoje rozumowanie

twonek
Mógłbym wyjaśnić, ale nie widzę sensu zrobienia tego dla kogoś, kto tylko przychodzi żeby bić pianę i obrażać rozmówcę, nie przeczytając nawet pytania i odpowiedzi dokładnie.
AB
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 10 lat
  • Postów:26
0

Ja tylko dodam od siebie, ze zgodnie z dokumentacją, push_back jak i pop_back mają Complexity Constant.
Co znaczy(chyba, nie jestem pewny) że koszt operacji jest niezależny od rozmiaru kontenera.

edytowany 2x, ostatnio: abbq
twonek
to nie ta operacja jest problemem, tylko ta Twoja pętla sprawdzania unikalności wskaźnika przy każdej operacji dodawania
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
4

@gośćabc, Wiem że trudno ci to zrozumieć, więc przyjmij następujące rzeczy na wiarę:

  1. Koszt operacji wyszukania elementu wg wartości w deque wynosi O(n)
  2. Koszt operacji wyszukania elementu wg wartości w set wynosi O(log(n))
  3. n > log(n)

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
AB
Ale ja przecież nic nie wyszukuję, rozumiem, ze moja pętla musi przelecieć każdy element, no ale inaczej, bez używania żadnych drzew/kluczy zrobić się nie da.
gośćabc
no oni są z kosmosu i to niby ja nie czytam ze zrozumieniem
_13th_Dragon
@abbq, pętla w setToDelete(b2Body* obj) jeżeli nie jest wyszukiwaniem to czym jest?
gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
1
_13th_Dragon napisał(a):

@gośćabc, Wiem że trudno ci to zrozumieć, więc przyjmij następujące rzeczy na wiarę:

  1. Koszt operacji wyszukania elementu wg wartości w deque wynosi O(n)
  2. Koszt operacji wyszukania elementu wg wartości w set wynosi O(log(n))
  3. n > log(n)

zapomiałeś wspomnieć o kosztach insertu do set i deque, ale żeby było Ci łatwiej zrozumieć to daj wiarę temu, że dodanie elementu na końcu czy początku deque jest szybsze o std::set insert czy emplace

edit:

ale Bóg ma Cię w swojej opiece pewnie i Cię ukarze za półprawdy, które lubisz wypisywać

edytowany 1x, ostatnio: gośćabc
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:3 dni
  • Lokalizacja:Szczecin
3

Argument z operatorem< nie jest poprawny, ponieważ std::less ma specjalizację dla wskaźników (których porównanie w innym przypadku mogłoby być UB - jeśli nie są częścią tego samego obiektu lub tablicy).

zapomiałeś wspomnieć o kosztach insertu do set i deque, ale żeby było Ci łatwiej zrozumieć to daj wiarę temu, że dodanie elementu na końcu czy początku deque jest szybsze o std::set insert czy emplace
Ale @abbq tutaj nie robi samego push_back tylko find (ale dla "ułatwienia" pisze sobie pętlę) + push_back, czyli ma O(n) + O(1) = O(n).

Ja bym proponował std::unordered_set.


twonek
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 2 lata
  • Postów:2500
0
gośćabc napisał(a):

zapomiałeś wspomnieć o kosztach insertu do set i deque, ale żeby było Ci łatwiej zrozumieć to daj wiarę temu, że dodanie elementu na końcu czy początku deque jest szybsze o std::set insert czy emplace

No to przyjmij również za wiarę, że n + 1 > log(n) dla odpowiednio dużych n.

edytowany 2x, ostatnio: twonek
kq
Skąd drugie log(n)?
twonek
porąbało mi się od tej piany, oczywiście jest tylko jedno log(n) przy insert
gośćabc
  • Rejestracja:prawie 11 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Szczecin
  • Postów:500
0

@abbq musisz poprawić logikę tak, aby dodawać do kolejki raz, i mieć pewność, że nie dodasz tego samego wskaźnika drugi raz,

oni wolą, żebyś zrobił find zamiast poprawił błędy w logice, co już zasugerowałem chyba w 6 poście

AB
Niby jak miałbym to zrobic? Musiałbym chyba stworzyć jakiś dodatkowy, tymczasowy kontener i wyłapywać duplikaty przed usuwaniem
gośćabc
nie znam logiki, która się tam kryje
gośćabc
jeżeli chcesz robić find to użyj std::unordered_set, którym wspomniałem w swoim 1 poście i @kq w swoim
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
1

@gośćabc, Widzę że kolejny banalny problem jest dla ciebie niezbyt oczywisty, więc cię wytłumaczę "na palcach" w kodzie (od autora postu):

Kopiuj
 bool ok(true);
    for(const b2Body* b: toDelete)
    {
        if(b == obj) // sprawdź czy wskaźnik już był dodany. inaczej będzie crash
        {
        ok = false;
        }
    }
 
    if(ok) {
    toDelete.push_back(obj);
    }

wyraźnie widać (dla każdego myślącego i znającego C++ człowieka) że najpierw się sprawdza czy element istnieje w kontenerze po czym jeżeli nie istnieje to się go dodaje, więc

  1. Dla deque O(n) - sprawdzenie; O(1) - wstawienie razem O(n)
  2. Dla set O(log(n)) - sprawdzenie razem z wstawieniem; razem O(log(n))
  3. Mam nadzieje że to "n > log(n)" już sobie zanotowałeś.

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
gośćabc
ale Ty jesteś słaby z tego programowania serio, ja już nie piszę nic w tym wątku pozdrawiam (ręce do ziemi mi opadają)
_13th_Dragon
@gośćabc, wyjazdy personalne przy braku argumentów jest typową oznaką ... zresztą sam znajdziesz w sieci diagnozę.
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
0

@abbq, http://www.cplusplus.com/reference/unordered_set/unordered_set/
Ale podejrzewam że b2Body jest twoją własną klasą więc zastanów się nad:

Kopiuj
std::deque<b2Body*> toDelete;
void setToDelete(b2Body* obj)
{
    if(!obj->MarkToDelete)
    {
        obj->MarkToDelete=true;
        toDelete.push_back(obj);
    }
}
// oczywiście razem ze sposobem 2

przy takim podejściu deque jest lepsze, z tym że testy pokazują że przy dużych rozmiarach vector i tak przebija wydajnościowo.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 2x, ostatnio: _13th_Dragon
AB
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 10 lat
  • Postów:26
0

Dobra, ostatecznie przekonało mnie użycie std::unordered_set do rozwiązania tego problemu.
Dwa pytania:

  1. jeżeli zrobię kontener.insert(wskaźnik) funkcja nie będzie miała żadnego efektu, jeśli wskaźnik już jest, tak wiec nie muszę się martwić o duplikaty?
  2. Ważnym aspektem, o którym nie wspomniałem a powinienem, poza tym i tak za bardzo odeszliście od tematu wiec już wam nie przeszkadzałem, jest to ze kontener zazwyczaj nie będzie zawierał nawet 10 elementów! dlatego też mógłbym przeboleć te stracone nanosekundy.

Jeżeli mam racje co do pierwszego pytania, to moje ostateczne rozwiązanie wyglądałoby mniej wiecej tak:

Kopiuj
std::unordered_set<b2Body*> toDelete;
void World::setToDelete(b2Body* obj)
{
 toDelete.insert(obj);
}

  for(const auto o : toDelete)
  {
        world.DestroyBody(o);
    }
    toDelete.clear();

Co o nim sądzicie?

edytowany 2x, ostatnio: abbq
kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:3 dni
  • Lokalizacja:Szczecin
2
  1. Tak.
  2. To std::vector lub zostaw ten std::unordered_set dla wygody.

edytowany 1x, ostatnio: kq
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:3 miesiące
2

@abbq, jeżeli z jakichś racji bardziej sensownych niż: - "Bo nie" nie możesz zrobić tak jak napisałem tu: http://4programmers.net/Forum/1102286
to z unordered_set jest najlepiej.

Edit:

Kopiuj
std::vector<b2Body*> toDelete;
void setToDelete(b2Body* obj)
{
    if(obj->userData!=&toDelete)
    {
        obj->userData=&toDelete;
        toDelete.push_back(obj);
    }
}

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
Zobacz pozostały 1 komentarz
_13th_Dragon
No to zrób MyB2Body pochodzącą od B2Body i zawierającą jedno pole typu bool
AB
Wtedy nie będę mógł przekazać tego do innych funkcji z biblioteki. (poza wskaźnikiem/ref), poza tym rzadko będę coś usuwał / tylko niektóre typy objetków dlatego zostawię tak jak jest.
_13th_Dragon
A gdzieś jest to przekazywane przez wartość ?
AB
To dość skomplikowane, musiałbyś mieć znajomość z tą biblioteką żeby zrozumieć problem. Dostosowanie tego co proponujesz do tej biblioteki to przerost formy nad treścią.
_13th_Dragon
@abbq, no to się zapoznałem z tą biblioteką i poprawiłem ten post
AB
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 10 lat
  • Postów:26
0

@_13th_Dragon
Nieźle. Musisz mieć sporo wolnego czasu, że chciało Ci się zerknąć na tą bibliotekę :) Jednocześnie rozwiązałeś mój przyszły problem! Tak to jest, jak się nie zna wszystkich możliwości biblioteki.
Wielkie dzięki.

_13th_Dragon
Nie muszę, porównaj czas twego komentarzu: - "... musiałbyś mieć znajomość z tą biblioteką ...", z czasem korekty poprzedniego postu.
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)