Trudno mi wymyślić, jak przenieść element tablicy. Na przykład biorąc pod uwagę następujące kwestie:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
Jak mogę napisać funkcję, aby przenieść się 'd'
wcześniej 'b'
?
Czy 'a'
po 'c'
?
Po przeprowadzce wskaźniki pozostałych elementów powinny zostać zaktualizowane. Oznacza to, że w pierwszym przykładzie po przeniesieniu arr [0] będzie = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'mi'
Wygląda na to, że powinno to być całkiem proste, ale nie mogę się wokół tego owinąć.
javascript
arrays
Mark Brown
źródło
źródło
const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
init
itarget
.Odpowiedzi:
Jeśli chcesz wersję na npm, przeniesienie tablicy jest najbliższe tej odpowiedzi, chociaż nie jest to ta sama implementacja. Aby uzyskać więcej informacji, zobacz sekcję dotyczącą jego użytkowania. Poprzednią wersję tej odpowiedzi (która zmodyfikowała Array.prototype.move) można znaleźć na npm w array.prototype.move .
Miałem całkiem dobry sukces dzięki tej funkcji:
Pamiętaj, że ostatni
return
służy wyłącznie do celów testowych:splice
wykonuje operacje na tablicy w miejscu, więc zwrot nie jest konieczny. W związku z tymmove
jest to operacja lokalna. Jeśli chcesz tego uniknąć i zwrócić kopię, użyjslice
.Przechodzenie przez kod:
new_index
jest większa niż długość tablicy, chcemy (przypuszczam), aby poprawnie wypełnić tablicę nowymiundefined
s. Ten mały fragment zajmuje się tym, popychającundefined
tablicę, aż uzyskamy odpowiednią długość.arr.splice(old_index, 1)[0]
łączymy stary element.splice
zwraca element, który został wycięty, ale jest w tablicy. W naszym powyższym przykładzie tak było[1]
. Więc bierzemy pierwszy indeks tej tablicy, aby uzyskać1
tam surowe dane .splice
aby wstawić ten element w miejsce new_index. Ponieważ wstawiliśmy powyższą tablicę, jeślinew_index > arr.length
prawdopodobnie pojawi się ona we właściwym miejscu, chyba że zrobili coś dziwnego, jak podanie liczby ujemnej.Bardziej wymyślna wersja uwzględniająca ujemne wskaźniki:
Które powinny uwzględniać takie rzeczy jak
array_move([1, 2, 3], -1, -2)
poprawnie (przenieś ostatni element na drugie na ostatnie miejsce). Wynik powinien być[1, 3, 2]
.Tak czy inaczej, w swoim pierwotnym pytaniu, byś zrobił
array_move(arr, 0, 2)
dlaa
POc
. Dlad
przedb
, byś zrobiłarray_move(arr, 3, 1)
.źródło
.hasOwnProperty
testu podczas iteracji z rzeczami takimi jak for..in, szczególnie z bibliotekami takimi jak Prototype i MooTools, które modyfikują prototypy. W każdym razie nie czułem, że jest to szczególnie ważna kwestia w stosunkowo ograniczonym przykładzie, takim jak ten, i istnieje spory podział w społeczności, czy modyfikacja prototypu jest dobrym pomysłem. Zwykle jednak problemy z iteracją stanowią najmniejszy problem.this[new_index] = undefined;
wif
bloku. Ponieważ tablice JavaScript są rzadkie, zwiększy to rozmiar tablicy, aby uwzględnić new_index,.splice
aby działał, ale bez konieczności tworzenia jakichkolwiek elementów pośrednich.this[new_index] = undefined
spowoduje umieszczenie znakuundefined
w gnieździe tablicy przed właściwym indeksem. (Np.[1,2,3].move(0,10)
Będzie miał1
w gnieździe 10 iundefined
w gnieździe 9.) Raczej, jeśli rzadkość jest OK, moglibyśmy obejść sięthis[new_index] = this.splice(old_index, 1)[0]
bez drugiego wywołania splicingu ( zamiast tego należy ustawić if / else).Oto jedna linijka, którą znalazłem na JSPerf ....
co jest niesamowite do czytania, ale jeśli chcesz wydajności (w małych zestawach danych) spróbuj ...
Nie mogę uwierzyć , to wszystko powinno iść do Richarda Scarrotta . W tym teście wydajności pokonuje metodę opartą na spawaniu dla mniejszych zestawów danych . Jest to jednak znacznie wolniejsze na większych zestawach danych, jak podkreśla Darwayne .
źródło
from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Lubię to. Jest zwięzły i działa.
Uwaga: zawsze pamiętaj o sprawdzeniu granic tablicy.
Uruchom Snippet na jsFiddle
źródło
ponieważ funkcja jest łańcuchowa, działa to również:
demo tutaj
źródło
Mój 2c. Łatwy do odczytania, działa, jest szybki, nie tworzy nowych tablic.
źródło
array
, tak jak to zrobiono na końcu.Wpadłem na pomysł @Reid pchania czegoś w miejsce elementu, który ma zostać przesunięty, aby utrzymać stały rozmiar tablicy. To upraszcza obliczenia. Ponadto pchanie pustego obiektu daje dodatkowe korzyści wynikające z możliwości jego unikatowego wyszukiwania później. Działa to, ponieważ dwa obiekty nie są równe, dopóki nie odnoszą się do tego samego obiektu.
Oto funkcja, która pobiera tablicę źródłową i indeksy źródłowe, docelowe. W razie potrzeby możesz dodać go do Array.prototype.
źródło
sourceIndex = 0
,destIndex = 1
destIndex
ma być indeksem przed przeniesieniem elementu źródłowego do tablicy.Jest to oparte na rozwiązaniu @ Reid. Z wyjątkiem:
Array
prototypu.undefined
przedmiotów, po prostu przesuwa je do pozycji najbardziej po prawej.Funkcjonować:
Testy jednostkowe:
źródło
Oto moje jednoelementowe rozwiązanie ES6 z opcjonalnym parametrem
on
.Dostosowanie pierwszego rozwiązania zaproponowanego przez
digiguru
Ten parametr
on
określa liczbę elementów zaczynających się odfrom
przeniesienia.źródło
Jednym z podejść byłoby utworzenie nowej tablicy z kawałkami w żądanej kolejności, przy użyciu metody wycinania.
Przykład
źródło
arr2
, że w wyniku operacji konkatenacji twoja postać jest ciągiem, prawda? :) W końcu jest"adc,de"
.splice
MetodaArray
może pomóc: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splicePamiętaj, że może to być stosunkowo drogie, ponieważ musi aktywnie ponownie indeksować tablicę.
źródło
Możesz zaimplementować podstawowy rachunek różniczkowy i stworzyć uniwersalną funkcję do przenoszenia elementu tablicy z jednej pozycji do drugiej.
W przypadku JavaScript wygląda to tak:
Sprawdź „ruchome elementy tablicy” w „gloommatter”, aby uzyskać szczegółowe wyjaśnienia.
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html
źródło
Wdrożyłem niezmienne
ECMAScript 6
rozwiązanie oparte na@Merc
odpowiedzi tutaj:Nazwy zmiennych można skracać, po prostu używać długich, aby kod mógł się wyjaśnić.
źródło
array
natychmiastfromIndex === toIndex
i stworzyć tylko,newArray
jeśli tak nie jest? Niezmienność nie oznacza, że należy utworzyć jedną nową kopię na wywołanie funkcji, nawet jeśli nie ma zmian. Samo pytanie b / c motywem zwiększonej długości tej funkcji (w stosunku do jedno-liniowych splicingu) jest wydajność ifromIndex
może często być równatoIndex
, w zależności od zastosowania.Potrzebowałem niezmiennej metody przenoszenia (takiej, która nie zmieniła oryginalnej tablicy), więc dostosowałem zaakceptowaną odpowiedź @ Reida, aby po prostu użyć Object.assign do utworzenia kopii tablicy przed wykonaniem łączenia.
Oto jsfiddle pokazujący go w akcji .
źródło
http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview
źródło
Skończyło się na tym, że połączyłem dwa z nich, aby działać trochę lepiej, gdy poruszam się zarówno na małe, jak i duże odległości. Otrzymuję dość spójne wyniki, ale prawdopodobnie ktoś bystrzejszy ode mnie może go trochę ulepszyć, aby działał inaczej dla różnych rozmiarów itp.
Korzystanie z niektórych innych metod podczas przemieszczania obiektów na małe odległości było znacznie szybsze (x10) niż stosowanie łączenia. Może się to zmieniać w zależności od długości macierzy, ale dotyczy to dużych tablic.
http://jsperf.com/arraymove-many-sizes
źródło
W wielu miejscach ( dodawanie niestandardowych funkcji do Array.prototype ) granie z prototypem Array może być złym pomysłem, w każdym razie połączyłem najlepsze z różnych postów, przyszło mi to przy użyciu nowoczesnego Javascript:
Nadzieja może być przydatna dla każdego
źródło
Ta wersja nie jest idealna do wszystkich celów i nie wszyscy lubią wyrażenia przecinkowe, ale tutaj jest jeden wiersz, który jest czystym wyrażeniem, tworząc nową kopię:
Wersja nieco poprawiona pod względem wydajności zwraca tablicę wejściową, jeśli nie jest wymagany żaden ruch, jest nadal OK dla niezmiennego użycia, ponieważ tablica się nie zmieni, a to wciąż czyste wyrażenie:
Wywołanie któregokolwiek z nich jest
tzn. polega na rozpowszechnianiu w celu wygenerowania nowej kopii. Użycie stałej arity 3
move
zagroziłoby albo właściwości pojedynczego wyrażenia, albo nieniszczącej naturze, albo korzyści wydajnościsplice
. Ponownie, jest to bardziej przykład spełniający pewne kryteria niż sugestia do zastosowania produkcyjnego.źródło
Array.move.js
Podsumowanie
Przenosi elementy wewnątrz tablicy, zwracając tablicę zawierającą przeniesione elementy.
Składnia
Parametry
indeks : Indeks, w którym należy przenosić elementy. Jeśli ujemna, indeks rozpocznie się od końca.
howMany : liczba elementów do przeniesienia z indeksu .
toIndex : Indeks tablicy, w której należy umieścić przeniesione elementy. Jeśli ujemny, toIndex rozpocznie się od końca.
Stosowanie
Polyfill
źródło
.move
wygląda na to, że powinien działać (nie testowałem go), należy pamiętać, że nie jest on częścią żadnego standardu. Dobrze jest też ostrzec ludzi, że funkcje wypełniania / wstawiania małp mogą uszkodzić część kodu, który zakłada, że wszystko, co jest policzalne, należy do nich.Użyłem ładnej odpowiedzi @Reid , ale zmagałem się z przenoszeniem elementu z końca tablicy o krok dalej - na początek (jak w pętli ). Np. [„A”, „b”, „c”] powinien stać się [„c”, „a”, „b”] przez wywołanie .move (2,3)
Osiągnąłem to, zmieniając wielkość liter dla new_index> = this.length.
źródło
Jako dodatek do doskonałej odpowiedzi Reida (i ponieważ nie mogę komentować); Możesz użyć modulo, aby zarówno wskaźniki ujemne, jak i zbyt duże były „najeżdżane”:
źródło
źródło
Myślałem, że to problem wymiany, ale tak nie jest. Oto moje jedno-liniowe rozwiązanie:
Oto mały test:
źródło
wynik:
źródło
źródło
źródło
Wersja niezmienna bez kopiowania tablicy:
źródło
Myślę, że najlepszym sposobem jest zdefiniowanie nowej właściwości tablic
źródło
Kolejny czysty wariant JS wykorzystujący operator rozprzestrzeniania się macierzy ES6 bez mutacji
źródło
Ta metoda zachowa oryginalną tablicę i sprawdzi błędy graniczne.
źródło